2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "control_protocol/control_protocol.h"
77 #include "analysis_window.h"
78 #include "audio_clock.h"
79 #include "audio_region_view.h"
80 #include "audio_streamview.h"
81 #include "audio_time_axis.h"
82 #include "automation_time_axis.h"
83 #include "bundle_manager.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , videotl_label (_("Video Timeline"))
250 , edit_packer (4, 4, true)
252 /* the values here don't matter: layout widgets
253 reset them as needed.
256 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
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)))
269 , image_socket_listener(0)
274 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
275 , meters_running(false)
276 , _pending_locate_request (false)
277 , _pending_initial_locate (false)
278 , _last_cut_copy_source_track (0)
280 , _region_selection_change_updates_region_list (true)
281 , _following_mixer_selection (false)
282 , _control_point_toggled_on_press (false)
283 , _stepping_axis_view (0)
287 /* we are a singleton */
289 PublicEditor::_instance = this;
293 selection = new Selection (this);
294 cut_buffer = new Selection (this);
296 clicked_regionview = 0;
297 clicked_axisview = 0;
298 clicked_routeview = 0;
299 clicked_control_point = 0;
300 last_update_frame = 0;
301 pre_press_cursor = 0;
302 _drags = new DragManager (this);
303 current_mixer_strip = 0;
306 snap_type_strings = I18N (_snap_type_strings);
307 snap_mode_strings = I18N (_snap_mode_strings);
308 zoom_focus_strings = I18N (_zoom_focus_strings);
309 edit_point_strings = I18N (_edit_point_strings);
310 #ifdef USE_RUBBERBAND
311 rb_opt_strings = I18N (_rb_opt_strings);
315 snap_threshold = 5.0;
316 bbt_beat_subdivision = 4;
319 last_autoscroll_x = 0;
320 last_autoscroll_y = 0;
321 autoscroll_active = false;
322 autoscroll_timeout_tag = -1;
327 current_interthread_info = 0;
328 _show_measures = true;
330 show_gain_after_trim = false;
332 have_pending_keyboard_selection = false;
333 _follow_playhead = true;
334 _stationary_playhead = false;
335 editor_ruler_menu = 0;
336 no_ruler_shown_update = false;
338 range_marker_menu = 0;
339 marker_menu_item = 0;
340 tempo_or_meter_marker_menu = 0;
341 transport_marker_menu = 0;
342 new_transport_marker_menu = 0;
343 editor_mixer_strip_width = Wide;
344 show_editor_mixer_when_tracks_arrive = false;
345 region_edit_menu_split_multichannel_item = 0;
346 region_edit_menu_split_item = 0;
349 current_stepping_trackview = 0;
351 entered_regionview = 0;
353 clear_entered_track = false;
356 button_release_can_deselect = true;
357 _dragging_playhead = false;
358 _dragging_edit_point = false;
359 select_new_marker = false;
361 layering_order_editor = 0;
362 no_save_visual = false;
364 within_track_canvas = false;
366 scrubbing_direction = 0;
370 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
371 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
372 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
373 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
374 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
376 _edit_point = EditAtMouse;
377 _internal_editing = false;
378 current_canvas_cursor = 0;
380 frames_per_unit = 2048; /* too early to use reset_zoom () */
382 _scroll_callbacks = 0;
384 zoom_focus = ZoomFocusLeft;
385 set_zoom_focus (ZoomFocusLeft);
386 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
388 bbt_label.set_name ("EditorRulerLabel");
389 bbt_label.set_size_request (-1, (int)timebar_height);
390 bbt_label.set_alignment (1.0, 0.5);
391 bbt_label.set_padding (5,0);
393 bbt_label.set_no_show_all();
394 minsec_label.set_name ("EditorRulerLabel");
395 minsec_label.set_size_request (-1, (int)timebar_height);
396 minsec_label.set_alignment (1.0, 0.5);
397 minsec_label.set_padding (5,0);
398 minsec_label.hide ();
399 minsec_label.set_no_show_all();
400 timecode_label.set_name ("EditorRulerLabel");
401 timecode_label.set_size_request (-1, (int)timebar_height);
402 timecode_label.set_alignment (1.0, 0.5);
403 timecode_label.set_padding (5,0);
404 timecode_label.hide ();
405 timecode_label.set_no_show_all();
406 samples_label.set_name ("EditorRulerLabel");
407 samples_label.set_size_request (-1, (int)timebar_height);
408 samples_label.set_alignment (1.0, 0.5);
409 samples_label.set_padding (5,0);
410 samples_label.hide ();
411 samples_label.set_no_show_all();
413 tempo_label.set_name ("EditorRulerLabel");
414 tempo_label.set_size_request (-1, (int)timebar_height);
415 tempo_label.set_alignment (1.0, 0.5);
416 tempo_label.set_padding (5,0);
418 tempo_label.set_no_show_all();
420 meter_label.set_name ("EditorRulerLabel");
421 meter_label.set_size_request (-1, (int)timebar_height);
422 meter_label.set_alignment (1.0, 0.5);
423 meter_label.set_padding (5,0);
425 meter_label.set_no_show_all();
427 mark_label.set_name ("EditorRulerLabel");
428 mark_label.set_size_request (-1, (int)timebar_height);
429 mark_label.set_alignment (1.0, 0.5);
430 mark_label.set_padding (5,0);
432 mark_label.set_no_show_all();
434 cd_mark_label.set_name ("EditorRulerLabel");
435 cd_mark_label.set_size_request (-1, (int)timebar_height);
436 cd_mark_label.set_alignment (1.0, 0.5);
437 cd_mark_label.set_padding (5,0);
438 cd_mark_label.hide();
439 cd_mark_label.set_no_show_all();
441 videotl_bar_height = 4;
442 videotl_label.set_name ("EditorRulerLabel");
443 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
444 videotl_label.set_alignment (1.0, 0.5);
445 videotl_label.set_padding (5,0);
446 videotl_label.hide();
447 videotl_label.set_no_show_all();
449 range_mark_label.set_name ("EditorRulerLabel");
450 range_mark_label.set_size_request (-1, (int)timebar_height);
451 range_mark_label.set_alignment (1.0, 0.5);
452 range_mark_label.set_padding (5,0);
453 range_mark_label.hide();
454 range_mark_label.set_no_show_all();
456 transport_mark_label.set_name ("EditorRulerLabel");
457 transport_mark_label.set_size_request (-1, (int)timebar_height);
458 transport_mark_label.set_alignment (1.0, 0.5);
459 transport_mark_label.set_padding (5,0);
460 transport_mark_label.hide();
461 transport_mark_label.set_no_show_all();
463 initialize_rulers ();
464 initialize_canvas ();
466 _summary = new EditorSummary (this);
468 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
469 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
471 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
473 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
474 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
476 edit_controls_vbox.set_spacing (0);
477 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
478 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
480 HBox* h = manage (new HBox);
481 _group_tabs = new EditorGroupTabs (this);
482 h->pack_start (*_group_tabs, PACK_SHRINK);
483 h->pack_start (edit_controls_vbox);
484 controls_layout.add (*h);
486 controls_layout.set_name ("EditControlsBase");
487 controls_layout.add_events (Gdk::SCROLL_MASK);
488 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
490 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
491 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
493 _cursors = new MouseCursors;
495 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
496 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
497 0.0, 1.0, 100.0, 1.0));
499 pad_line_1->property_color_rgba() = 0xFF0000FF;
504 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
505 time_canvas_vbox.set_size_request (-1, -1);
507 ruler_label_event_box.add (ruler_label_vbox);
508 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 time_button_event_box.add (time_button_vbox);
512 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
513 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
515 /* these enable us to have a dedicated window (for cursor setting, etc.)
516 for the canvas areas.
519 track_canvas_event_box.add (*track_canvas);
521 time_canvas_event_box.add (time_canvas_vbox);
522 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
524 edit_packer.set_col_spacings (0);
525 edit_packer.set_row_spacings (0);
526 edit_packer.set_homogeneous (false);
527 edit_packer.set_border_width (0);
528 edit_packer.set_name ("EditorWindow");
530 /* labels for the rulers */
531 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
532 /* labels for the marker "tracks" */
533 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
535 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
537 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
539 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
541 bottom_hbox.set_border_width (2);
542 bottom_hbox.set_spacing (3);
544 _route_groups = new EditorRouteGroups (this);
545 _routes = new EditorRoutes (this);
546 _regions = new EditorRegions (this);
547 _snapshots = new EditorSnapshots (this);
548 _locations = new EditorLocations (this);
550 add_notebook_page (_("Regions"), _regions->widget ());
551 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
552 add_notebook_page (_("Snapshots"), _snapshots->widget ());
553 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
554 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
556 _the_notebook.set_show_tabs (true);
557 _the_notebook.set_scrollable (true);
558 _the_notebook.popup_disable ();
559 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
560 _the_notebook.show_all ();
562 _notebook_shrunk = false;
564 editor_summary_pane.pack1(edit_packer);
566 Button* summary_arrows_left_left = manage (new Button);
567 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
568 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
569 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
571 Button* summary_arrows_left_right = manage (new Button);
572 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
573 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
574 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 VBox* summary_arrows_left = manage (new VBox);
577 summary_arrows_left->pack_start (*summary_arrows_left_left);
578 summary_arrows_left->pack_start (*summary_arrows_left_right);
580 Button* summary_arrows_right_up = manage (new Button);
581 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
582 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
583 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_right_down = manage (new Button);
586 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
587 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
588 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_right = manage (new VBox);
591 summary_arrows_right->pack_start (*summary_arrows_right_up);
592 summary_arrows_right->pack_start (*summary_arrows_right_down);
594 Frame* summary_frame = manage (new Frame);
595 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
597 summary_frame->add (*_summary);
598 summary_frame->show ();
600 _summary_hbox.pack_start (*summary_arrows_left, false, false);
601 _summary_hbox.pack_start (*summary_frame, true, true);
602 _summary_hbox.pack_start (*summary_arrows_right, false, false);
604 editor_summary_pane.pack2 (_summary_hbox);
606 edit_pane.pack1 (editor_summary_pane, true, true);
607 edit_pane.pack2 (_the_notebook, false, true);
609 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
611 /* XXX: editor_summary_pane might need similar to the edit_pane */
613 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
615 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
616 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
618 top_hbox.pack_start (toolbar_frame);
620 HBox *hbox = manage (new HBox);
621 hbox->pack_start (edit_pane, true, true);
623 global_vpacker.pack_start (top_hbox, false, false);
624 global_vpacker.pack_start (*hbox, true, true);
626 global_hpacker.pack_start (global_vpacker, true, true);
628 set_name ("EditorWindow");
629 add_accel_group (ActionManager::ui_manager->get_accel_group());
631 status_bar_hpacker.show ();
633 vpacker.pack_end (status_bar_hpacker, false, false);
634 vpacker.pack_end (global_hpacker, true, true);
636 /* register actions now so that set_state() can find them and set toggles/checks etc */
639 /* when we start using our own keybinding system for the editor, this
640 * will be uncommented
646 _snap_type = SnapToBeat;
647 set_snap_to (_snap_type);
648 _snap_mode = SnapOff;
649 set_snap_mode (_snap_mode);
650 set_mouse_mode (MouseObject, true);
651 pre_internal_mouse_mode = MouseObject;
652 pre_internal_snap_type = _snap_type;
653 pre_internal_snap_mode = _snap_mode;
654 internal_snap_type = _snap_type;
655 internal_snap_mode = _snap_mode;
656 set_edit_point_preference (EditAtMouse, true);
658 _playlist_selector = new PlaylistSelector();
659 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
661 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
665 nudge_forward_button.set_name ("zoom button");
666 nudge_forward_button.add_elements (ArdourButton::FlatFace);
667 nudge_forward_button.set_image(::get_icon("nudge_right"));
669 nudge_backward_button.set_name ("zoom button");
670 nudge_backward_button.add_elements (ArdourButton::FlatFace);
671 nudge_backward_button.set_image(::get_icon("nudge_left"));
673 fade_context_menu.set_name ("ArdourContextMenu");
675 /* icons, titles, WM stuff */
677 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
678 Glib::RefPtr<Gdk::Pixbuf> icon;
680 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
684 window_icons.push_back (icon);
686 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
687 window_icons.push_back (icon);
689 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
690 window_icons.push_back (icon);
692 if (!window_icons.empty()) {
693 // set_icon_list (window_icons);
694 set_default_icon_list (window_icons);
697 WindowTitle title(Glib::get_application_name());
698 title += _("Editor");
699 set_title (title.get_string());
700 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
703 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
705 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
706 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
708 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
710 /* allow external control surfaces/protocols to do various things */
712 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
713 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
714 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
715 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
716 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
717 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
718 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
719 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
720 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
721 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
722 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
723 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
724 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
725 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
727 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
728 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
729 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
730 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
731 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
733 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
735 /* problematic: has to return a value and thus cannot be x-thread */
737 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
739 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
741 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
743 _ignore_region_action = false;
744 _last_region_menu_was_main = false;
745 _popup_region_menu_item = 0;
747 _show_marker_lines = false;
748 _over_region_trim_target = false;
750 /* Button bindings */
752 button_bindings = new Bindings;
754 XMLNode* node = button_settings();
756 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
757 button_bindings->load (**i);
764 setup_fade_images ();
770 if(image_socket_listener) {
771 if(image_socket_listener->is_connected())
773 image_socket_listener->close_connection() ;
776 delete image_socket_listener ;
777 image_socket_listener = 0 ;
781 delete button_bindings;
783 delete _route_groups;
789 Editor::button_settings () const
791 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
792 XMLNode* node = find_named_node (*settings, X_("Buttons"));
795 node = new XMLNode (X_("Buttons"));
802 Editor::add_toplevel_controls (Container& cont)
804 vpacker.pack_start (cont, false, false);
809 Editor::get_smart_mode () const
811 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
815 Editor::catch_vanishing_regionview (RegionView *rv)
817 /* note: the selection will take care of the vanishing
818 audioregionview by itself.
821 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
825 if (clicked_regionview == rv) {
826 clicked_regionview = 0;
829 if (entered_regionview == rv) {
830 set_entered_regionview (0);
833 if (!_all_region_actions_sensitized) {
834 sensitize_all_region_actions (true);
837 _over_region_trim_target = false;
841 Editor::set_entered_regionview (RegionView* rv)
843 if (rv == entered_regionview) {
847 if (entered_regionview) {
848 entered_regionview->exited ();
851 if ((entered_regionview = rv) != 0) {
852 entered_regionview->entered (internal_editing ());
855 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
856 /* This RegionView entry might have changed what region actions
857 are allowed, so sensitize them all in case a key is pressed.
859 sensitize_all_region_actions (true);
864 Editor::set_entered_track (TimeAxisView* tav)
867 entered_track->exited ();
870 if ((entered_track = tav) != 0) {
871 entered_track->entered ();
876 Editor::show_window ()
878 if (!is_visible ()) {
881 /* XXX: this is a bit unfortunate; it would probably
882 be nicer if we could just call show () above rather
883 than needing the show_all ()
886 /* re-hide stuff if necessary */
887 editor_list_button_toggled ();
888 parameter_changed ("show-summary");
889 parameter_changed ("show-group-tabs");
890 parameter_changed ("show-zoom-tools");
892 /* now reset all audio_time_axis heights, because widgets might need
898 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
899 tv = (static_cast<TimeAxisView*>(*i));
903 if (current_mixer_strip) {
904 current_mixer_strip->hide_things ();
905 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
913 Editor::instant_save ()
915 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
920 _session->add_instant_xml(get_state());
922 Config->add_instant_xml(get_state());
927 Editor::zoom_adjustment_changed ()
933 double fpu = zoom_range_clock->current_duration() / _canvas_width;
934 bool clamped = clamp_frames_per_unit (fpu);
937 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
944 Editor::control_vertical_zoom_in_all ()
946 tav_zoom_smooth (false, true);
950 Editor::control_vertical_zoom_out_all ()
952 tav_zoom_smooth (true, true);
956 Editor::control_vertical_zoom_in_selected ()
958 tav_zoom_smooth (false, false);
962 Editor::control_vertical_zoom_out_selected ()
964 tav_zoom_smooth (true, false);
968 Editor::control_view (uint32_t view)
970 goto_visual_state (view);
974 Editor::control_unselect ()
976 selection->clear_tracks ();
980 Editor::control_select (uint32_t rid, Selection::Operation op)
982 /* handles the (static) signal from the ControlProtocol class that
983 * requests setting the selected track to a given RID
990 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
996 TimeAxisView* tav = axis_view_from_route (r);
1000 case Selection::Add:
1001 selection->add (tav);
1003 case Selection::Toggle:
1004 selection->toggle (tav);
1006 case Selection::Extend:
1008 case Selection::Set:
1009 selection->set (tav);
1013 selection->clear_tracks ();
1018 Editor::control_step_tracks_up ()
1020 scroll_tracks_up_line ();
1024 Editor::control_step_tracks_down ()
1026 scroll_tracks_down_line ();
1030 Editor::control_scroll (float fraction)
1032 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1038 double step = fraction * current_page_frames();
1041 _control_scroll_target is an optional<T>
1043 it acts like a pointer to an framepos_t, with
1044 a operator conversion to boolean to check
1045 that it has a value could possibly use
1046 playhead_cursor->current_frame to store the
1047 value and a boolean in the class to know
1048 when it's out of date
1051 if (!_control_scroll_target) {
1052 _control_scroll_target = _session->transport_frame();
1053 _dragging_playhead = true;
1056 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1057 *_control_scroll_target = 0;
1058 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1059 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1061 *_control_scroll_target += (framepos_t) floor (step);
1064 /* move visuals, we'll catch up with it later */
1066 playhead_cursor->set_position (*_control_scroll_target);
1067 UpdateAllTransportClocks (*_control_scroll_target);
1069 if (*_control_scroll_target > (current_page_frames() / 2)) {
1070 /* try to center PH in window */
1071 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1077 Now we do a timeout to actually bring the session to the right place
1078 according to the playhead. This is to avoid reading disk buffers on every
1079 call to control_scroll, which is driven by ScrollTimeline and therefore
1080 probably by a control surface wheel which can generate lots of events.
1082 /* cancel the existing timeout */
1084 control_scroll_connection.disconnect ();
1086 /* add the next timeout */
1088 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1092 Editor::deferred_control_scroll (framepos_t /*target*/)
1094 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1095 // reset for next stream
1096 _control_scroll_target = boost::none;
1097 _dragging_playhead = false;
1102 Editor::access_action (std::string action_group, std::string action_item)
1108 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1111 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1119 Editor::on_realize ()
1121 Window::on_realize ();
1126 Editor::map_position_change (framepos_t frame)
1128 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1130 if (_session == 0) {
1134 if (_follow_playhead) {
1135 center_screen (frame);
1138 playhead_cursor->set_position (frame);
1142 Editor::center_screen (framepos_t frame)
1144 double page = _canvas_width * frames_per_unit;
1146 /* if we're off the page, then scroll.
1149 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1150 center_screen_internal (frame, page);
1155 Editor::center_screen_internal (framepos_t frame, float page)
1160 frame -= (framepos_t) page;
1165 reset_x_origin (frame);
1170 Editor::update_title ()
1172 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1175 bool dirty = _session->dirty();
1177 string session_name;
1179 if (_session->snap_name() != _session->name()) {
1180 session_name = _session->snap_name();
1182 session_name = _session->name();
1186 session_name = "*" + session_name;
1189 WindowTitle title(session_name);
1190 title += Glib::get_application_name();
1191 set_title (title.get_string());
1193 /* ::session_going_away() will have taken care of it */
1198 Editor::set_session (Session *t)
1200 SessionHandlePtr::set_session (t);
1206 zoom_range_clock->set_session (_session);
1207 _playlist_selector->set_session (_session);
1208 nudge_clock->set_session (_session);
1209 _summary->set_session (_session);
1210 _group_tabs->set_session (_session);
1211 _route_groups->set_session (_session);
1212 _regions->set_session (_session);
1213 _snapshots->set_session (_session);
1214 _routes->set_session (_session);
1215 _locations->set_session (_session);
1217 if (rhythm_ferret) {
1218 rhythm_ferret->set_session (_session);
1221 if (analysis_window) {
1222 analysis_window->set_session (_session);
1226 sfbrowser->set_session (_session);
1229 compute_fixed_ruler_scale ();
1231 /* Make sure we have auto loop and auto punch ranges */
1233 Location* loc = _session->locations()->auto_loop_location();
1235 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1237 if (loc->start() == loc->end()) {
1238 loc->set_end (loc->start() + 1);
1241 _session->locations()->add (loc, false);
1242 _session->set_auto_loop_location (loc);
1245 loc->set_name (_("Loop"));
1248 loc = _session->locations()->auto_punch_location();
1251 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1253 if (loc->start() == loc->end()) {
1254 loc->set_end (loc->start() + 1);
1257 _session->locations()->add (loc, false);
1258 _session->set_auto_punch_location (loc);
1261 loc->set_name (_("Punch"));
1264 refresh_location_display ();
1266 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1267 the selected Marker; this needs the LocationMarker list to be available.
1269 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1270 set_state (*node, Stateful::loading_state_version);
1272 /* catch up with the playhead */
1274 _session->request_locate (playhead_cursor->current_frame);
1275 _pending_initial_locate = true;
1279 /* These signals can all be emitted by a non-GUI thread. Therefore the
1280 handlers for them must not attempt to directly interact with the GUI,
1281 but use Gtkmm2ext::UI::instance()->call_slot();
1284 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1285 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1286 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1287 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1288 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1289 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1290 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1291 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1292 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1293 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1294 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1295 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1296 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1297 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1299 playhead_cursor->canvas_item.show ();
1301 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1302 Config->map_parameters (pc);
1303 _session->config.map_parameters (pc);
1305 restore_ruler_visibility ();
1306 //tempo_map_changed (PropertyChange (0));
1307 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1309 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1310 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1313 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1314 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1317 switch (_snap_type) {
1318 case SnapToRegionStart:
1319 case SnapToRegionEnd:
1320 case SnapToRegionSync:
1321 case SnapToRegionBoundary:
1322 build_region_boundary_cache ();
1329 /* register for undo history */
1330 _session->register_with_memento_command_factory(id(), this);
1332 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1334 start_updating_meters ();
1338 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1340 if (a->get_name() == "RegionMenu") {
1341 /* When the main menu's region menu is opened, we setup the actions so that they look right
1342 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1343 so we resensitize all region actions when the entered regionview or the region selection
1344 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1345 happens after the region context menu is opened. So we set a flag here, too.
1349 sensitize_the_right_region_actions ();
1350 _last_region_menu_was_main = true;
1355 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1357 using namespace Menu_Helpers;
1359 void (Editor::*emf)(FadeShape);
1360 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1363 images = &_xfade_in_images;
1364 emf = &Editor::set_fade_in_shape;
1366 images = &_xfade_out_images;
1367 emf = &Editor::set_fade_out_shape;
1372 _("Linear (for highly correlated material)"),
1373 *(*images)[FadeLinear],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 _("Constant power"),
1383 *(*images)[FadeConstantPower],
1384 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeSymmetric],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1397 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402 *(*images)[FadeSlow],
1403 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1406 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1411 *(*images)[FadeFast],
1412 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1415 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 /** Pop up a context menu for when the user clicks on a start crossfade */
1420 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1422 using namespace Menu_Helpers;
1424 MenuList& items (xfade_in_context_menu.items());
1426 if (items.empty()) {
1427 fill_xfade_menu (items, true);
1430 xfade_in_context_menu.popup (button, time);
1433 /** Pop up a context menu for when the user clicks on an end crossfade */
1435 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1437 using namespace Menu_Helpers;
1439 MenuList& items (xfade_out_context_menu.items());
1441 if (items.empty()) {
1442 fill_xfade_menu (items, false);
1445 xfade_out_context_menu.popup (button, time);
1449 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1451 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1453 using namespace Menu_Helpers;
1454 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1457 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1461 MenuList& items (fade_context_menu.items());
1464 switch (item_type) {
1466 case FadeInHandleItem:
1467 if (arv->audio_region()->fade_in_active()) {
1468 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1470 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1473 items.push_back (SeparatorElem());
1475 if (Profile->get_sae()) {
1477 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1478 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1485 *_fade_in_images[FadeLinear],
1486 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *_fade_in_images[FadeSlow],
1496 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *_fade_in_images[FadeFast],
1505 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 *_fade_in_images[FadeSymmetric],
1514 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1519 _("Constant power"),
1520 *_fade_in_images[FadeConstantPower],
1521 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1524 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1530 case FadeOutHandleItem:
1531 if (arv->audio_region()->fade_out_active()) {
1532 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1534 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1537 items.push_back (SeparatorElem());
1539 if (Profile->get_sae()) {
1540 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1541 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1547 *_fade_out_images[FadeLinear],
1548 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1552 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1557 *_fade_out_images[FadeSlow],
1558 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1561 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1566 *_fade_out_images[FadeFast],
1567 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1570 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1575 *_fade_out_images[FadeSymmetric],
1576 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1581 _("Constant power"),
1582 *_fade_out_images[FadeConstantPower],
1583 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1586 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1592 fatal << _("programming error: ")
1593 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1598 fade_context_menu.popup (button, time);
1602 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1604 using namespace Menu_Helpers;
1605 Menu* (Editor::*build_menu_function)();
1608 switch (item_type) {
1610 case RegionViewName:
1611 case RegionViewNameHighlight:
1612 case LeftFrameHandle:
1613 case RightFrameHandle:
1614 if (with_selection) {
1615 build_menu_function = &Editor::build_track_selection_context_menu;
1617 build_menu_function = &Editor::build_track_region_context_menu;
1622 if (with_selection) {
1623 build_menu_function = &Editor::build_track_selection_context_menu;
1625 build_menu_function = &Editor::build_track_context_menu;
1630 if (clicked_routeview->track()) {
1631 build_menu_function = &Editor::build_track_context_menu;
1633 build_menu_function = &Editor::build_track_bus_context_menu;
1638 /* probably shouldn't happen but if it does, we don't care */
1642 menu = (this->*build_menu_function)();
1643 menu->set_name ("ArdourContextMenu");
1645 /* now handle specific situations */
1647 switch (item_type) {
1649 case RegionViewName:
1650 case RegionViewNameHighlight:
1651 case LeftFrameHandle:
1652 case RightFrameHandle:
1653 if (!with_selection) {
1654 if (region_edit_menu_split_item) {
1655 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1656 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1658 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1661 if (region_edit_menu_split_multichannel_item) {
1662 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1663 region_edit_menu_split_multichannel_item->set_sensitive (true);
1665 region_edit_menu_split_multichannel_item->set_sensitive (false);
1678 /* probably shouldn't happen but if it does, we don't care */
1682 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1684 /* Bounce to disk */
1686 using namespace Menu_Helpers;
1687 MenuList& edit_items = menu->items();
1689 edit_items.push_back (SeparatorElem());
1691 switch (clicked_routeview->audio_track()->freeze_state()) {
1692 case AudioTrack::NoFreeze:
1693 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1696 case AudioTrack::Frozen:
1697 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1700 case AudioTrack::UnFrozen:
1701 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1707 if (item_type == StreamItem && clicked_routeview) {
1708 clicked_routeview->build_underlay_menu(menu);
1711 /* When the region menu is opened, we setup the actions so that they look right
1714 sensitize_the_right_region_actions ();
1715 _last_region_menu_was_main = false;
1717 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1718 menu->popup (button, time);
1722 Editor::build_track_context_menu ()
1724 using namespace Menu_Helpers;
1726 MenuList& edit_items = track_context_menu.items();
1729 add_dstream_context_items (edit_items);
1730 return &track_context_menu;
1734 Editor::build_track_bus_context_menu ()
1736 using namespace Menu_Helpers;
1738 MenuList& edit_items = track_context_menu.items();
1741 add_bus_context_items (edit_items);
1742 return &track_context_menu;
1746 Editor::build_track_region_context_menu ()
1748 using namespace Menu_Helpers;
1749 MenuList& edit_items = track_region_context_menu.items();
1752 /* we've just cleared the track region context menu, so the menu that these
1753 two items were on will have disappeared; stop them dangling.
1755 region_edit_menu_split_item = 0;
1756 region_edit_menu_split_multichannel_item = 0;
1758 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1761 boost::shared_ptr<Track> tr;
1762 boost::shared_ptr<Playlist> pl;
1764 if ((tr = rtv->track())) {
1765 add_region_context_items (edit_items, tr);
1769 add_dstream_context_items (edit_items);
1771 return &track_region_context_menu;
1775 Editor::analyze_region_selection ()
1777 if (analysis_window == 0) {
1778 analysis_window = new AnalysisWindow();
1781 analysis_window->set_session(_session);
1783 analysis_window->show_all();
1786 analysis_window->set_regionmode();
1787 analysis_window->analyze();
1789 analysis_window->present();
1793 Editor::analyze_range_selection()
1795 if (analysis_window == 0) {
1796 analysis_window = new AnalysisWindow();
1799 analysis_window->set_session(_session);
1801 analysis_window->show_all();
1804 analysis_window->set_rangemode();
1805 analysis_window->analyze();
1807 analysis_window->present();
1811 Editor::build_track_selection_context_menu ()
1813 using namespace Menu_Helpers;
1814 MenuList& edit_items = track_selection_context_menu.items();
1815 edit_items.clear ();
1817 add_selection_context_items (edit_items);
1818 // edit_items.push_back (SeparatorElem());
1819 // add_dstream_context_items (edit_items);
1821 return &track_selection_context_menu;
1825 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1827 using namespace Menu_Helpers;
1829 /* OK, stick the region submenu at the top of the list, and then add
1833 RegionSelection rs = get_regions_from_selection_and_entered ();
1835 string::size_type pos = 0;
1836 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1838 /* we have to hack up the region name because "_" has a special
1839 meaning for menu titles.
1842 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1843 menu_item_name.replace (pos, 1, "__");
1847 if (_popup_region_menu_item == 0) {
1848 _popup_region_menu_item = new MenuItem (menu_item_name);
1849 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1850 _popup_region_menu_item->show ();
1852 _popup_region_menu_item->set_label (menu_item_name);
1855 const framepos_t position = get_preferred_edit_position (false, true);
1857 edit_items.push_back (*_popup_region_menu_item);
1858 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1859 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1861 edit_items.push_back (SeparatorElem());
1864 /** Add context menu items relevant to selection ranges.
1865 * @param edit_items List to add the items to.
1868 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1870 using namespace Menu_Helpers;
1872 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1873 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1878 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (
1882 _("Move Range Start to Previous Region Boundary"),
1883 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1887 edit_items.push_back (
1889 _("Move Range Start to Next Region Boundary"),
1890 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1894 edit_items.push_back (
1896 _("Move Range End to Previous Region Boundary"),
1897 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1901 edit_items.push_back (
1903 _("Move Range End to Next Region Boundary"),
1904 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1910 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1917 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1919 edit_items.push_back (SeparatorElem());
1920 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1924 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1925 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1927 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1929 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1930 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1931 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1932 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1937 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1939 using namespace Menu_Helpers;
1943 Menu *play_menu = manage (new Menu);
1944 MenuList& play_items = play_menu->items();
1945 play_menu->set_name ("ArdourContextMenu");
1947 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1948 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1949 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1950 play_items.push_back (SeparatorElem());
1951 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1953 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1957 Menu *select_menu = manage (new Menu);
1958 MenuList& select_items = select_menu->items();
1959 select_menu->set_name ("ArdourContextMenu");
1961 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1962 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1963 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1964 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1965 select_items.push_back (SeparatorElem());
1966 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1967 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1968 select_items.push_back (SeparatorElem());
1969 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1970 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1971 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1972 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1973 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1974 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1975 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1977 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1981 Menu *cutnpaste_menu = manage (new Menu);
1982 MenuList& cutnpaste_items = cutnpaste_menu->items();
1983 cutnpaste_menu->set_name ("ArdourContextMenu");
1985 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1986 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1987 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1989 cutnpaste_items.push_back (SeparatorElem());
1991 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1992 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1994 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1996 /* Adding new material */
1998 edit_items.push_back (SeparatorElem());
1999 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2000 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2004 Menu *nudge_menu = manage (new Menu());
2005 MenuList& nudge_items = nudge_menu->items();
2006 nudge_menu->set_name ("ArdourContextMenu");
2008 edit_items.push_back (SeparatorElem());
2009 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2010 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2011 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2012 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2014 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2018 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2020 using namespace Menu_Helpers;
2024 Menu *play_menu = manage (new Menu);
2025 MenuList& play_items = play_menu->items();
2026 play_menu->set_name ("ArdourContextMenu");
2028 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2029 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2030 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2034 Menu *select_menu = manage (new Menu);
2035 MenuList& select_items = select_menu->items();
2036 select_menu->set_name ("ArdourContextMenu");
2038 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2039 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2040 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2041 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2042 select_items.push_back (SeparatorElem());
2043 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2044 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2045 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2046 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2048 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2052 Menu *cutnpaste_menu = manage (new Menu);
2053 MenuList& cutnpaste_items = cutnpaste_menu->items();
2054 cutnpaste_menu->set_name ("ArdourContextMenu");
2056 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2057 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2058 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2060 Menu *nudge_menu = manage (new Menu());
2061 MenuList& nudge_items = nudge_menu->items();
2062 nudge_menu->set_name ("ArdourContextMenu");
2064 edit_items.push_back (SeparatorElem());
2065 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2066 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2067 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2068 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2070 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2074 Editor::snap_type() const
2080 Editor::snap_mode() const
2086 Editor::set_snap_to (SnapType st)
2088 unsigned int snap_ind = (unsigned int)st;
2092 if (snap_ind > snap_type_strings.size() - 1) {
2094 _snap_type = (SnapType)snap_ind;
2097 string str = snap_type_strings[snap_ind];
2099 if (str != snap_type_selector.get_active_text()) {
2100 snap_type_selector.set_active_text (str);
2105 switch (_snap_type) {
2106 case SnapToBeatDiv128:
2107 case SnapToBeatDiv64:
2108 case SnapToBeatDiv32:
2109 case SnapToBeatDiv28:
2110 case SnapToBeatDiv24:
2111 case SnapToBeatDiv20:
2112 case SnapToBeatDiv16:
2113 case SnapToBeatDiv14:
2114 case SnapToBeatDiv12:
2115 case SnapToBeatDiv10:
2116 case SnapToBeatDiv8:
2117 case SnapToBeatDiv7:
2118 case SnapToBeatDiv6:
2119 case SnapToBeatDiv5:
2120 case SnapToBeatDiv4:
2121 case SnapToBeatDiv3:
2122 case SnapToBeatDiv2: {
2123 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2124 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2126 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2127 current_bbt_points_begin, current_bbt_points_end);
2128 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2129 current_bbt_points_begin, current_bbt_points_end);
2130 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2134 case SnapToRegionStart:
2135 case SnapToRegionEnd:
2136 case SnapToRegionSync:
2137 case SnapToRegionBoundary:
2138 build_region_boundary_cache ();
2146 SnapChanged (); /* EMIT SIGNAL */
2150 Editor::set_snap_mode (SnapMode mode)
2152 string str = snap_mode_strings[(int)mode];
2154 if (_internal_editing) {
2155 internal_snap_mode = mode;
2157 pre_internal_snap_mode = mode;
2162 if (str != snap_mode_selector.get_active_text ()) {
2163 snap_mode_selector.set_active_text (str);
2169 Editor::set_edit_point_preference (EditPoint ep, bool force)
2171 bool changed = (_edit_point != ep);
2174 string str = edit_point_strings[(int)ep];
2176 if (str != edit_point_selector.get_active_text ()) {
2177 edit_point_selector.set_active_text (str);
2180 set_canvas_cursor ();
2182 if (!force && !changed) {
2186 const char* action=NULL;
2188 switch (_edit_point) {
2189 case EditAtPlayhead:
2190 action = "edit-at-playhead";
2192 case EditAtSelectedMarker:
2193 action = "edit-at-marker";
2196 action = "edit-at-mouse";
2200 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2202 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2206 bool in_track_canvas;
2208 if (!mouse_frame (foo, in_track_canvas)) {
2209 in_track_canvas = false;
2212 reset_canvas_action_sensitivity (in_track_canvas);
2218 Editor::set_state (const XMLNode& node, int /*version*/)
2220 const XMLProperty* prop;
2227 g.base_width = default_width;
2228 g.base_height = default_height;
2232 if ((geometry = find_named_node (node, "geometry")) != 0) {
2236 if ((prop = geometry->property("x_size")) == 0) {
2237 prop = geometry->property ("x-size");
2240 g.base_width = atoi(prop->value());
2242 if ((prop = geometry->property("y_size")) == 0) {
2243 prop = geometry->property ("y-size");
2246 g.base_height = atoi(prop->value());
2249 if ((prop = geometry->property ("x_pos")) == 0) {
2250 prop = geometry->property ("x-pos");
2253 x = atoi (prop->value());
2256 if ((prop = geometry->property ("y_pos")) == 0) {
2257 prop = geometry->property ("y-pos");
2260 y = atoi (prop->value());
2264 set_default_size (g.base_width, g.base_height);
2267 if (_session && (prop = node.property ("playhead"))) {
2269 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2270 playhead_cursor->set_position (pos);
2272 playhead_cursor->set_position (0);
2275 if ((prop = node.property ("mixer-width"))) {
2276 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2279 if ((prop = node.property ("zoom-focus"))) {
2280 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2283 if ((prop = node.property ("zoom"))) {
2284 reset_zoom (PBD::atof (prop->value()));
2286 reset_zoom (frames_per_unit);
2289 if ((prop = node.property ("snap-to"))) {
2290 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2293 if ((prop = node.property ("snap-mode"))) {
2294 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2297 if ((prop = node.property ("internal-snap-to"))) {
2298 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2301 if ((prop = node.property ("internal-snap-mode"))) {
2302 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2305 if ((prop = node.property ("pre-internal-snap-to"))) {
2306 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2310 if ((prop = node.property ("pre-internal-snap-mode"))) {
2311 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2314 if ((prop = node.property ("mouse-mode"))) {
2315 MouseMode m = str2mousemode(prop->value());
2316 set_mouse_mode (m, true);
2318 set_mouse_mode (MouseObject, true);
2321 if ((prop = node.property ("left-frame")) != 0) {
2323 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2327 reset_x_origin (pos);
2331 if ((prop = node.property ("y-origin")) != 0) {
2332 reset_y_origin (atof (prop->value ()));
2335 if ((prop = node.property ("internal-edit"))) {
2336 bool yn = string_is_affirmative (prop->value());
2337 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2339 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2340 tact->set_active (!yn);
2341 tact->set_active (yn);
2345 if ((prop = node.property ("join-object-range"))) {
2346 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2347 bool yn = string_is_affirmative (prop->value());
2349 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2350 tact->set_active (!yn);
2351 tact->set_active (yn);
2353 set_mouse_mode(mouse_mode, true);
2356 if ((prop = node.property ("edit-point"))) {
2357 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2360 if ((prop = node.property ("show-measures"))) {
2361 bool yn = string_is_affirmative (prop->value());
2362 _show_measures = yn;
2363 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2365 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2366 /* do it twice to force the change */
2367 tact->set_active (!yn);
2368 tact->set_active (yn);
2372 if ((prop = node.property ("follow-playhead"))) {
2373 bool yn = string_is_affirmative (prop->value());
2374 set_follow_playhead (yn);
2375 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-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 ("stationary-playhead"))) {
2385 bool yn = string_is_affirmative (prop->value());
2386 set_stationary_playhead (yn);
2387 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2389 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2390 if (tact->get_active() != yn) {
2391 tact->set_active (yn);
2396 if ((prop = node.property ("region-list-sort-type"))) {
2397 RegionListSortType st;
2398 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2401 if ((prop = node.property ("show-editor-mixer"))) {
2403 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2406 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2407 bool yn = string_is_affirmative (prop->value());
2409 /* do it twice to force the change */
2411 tact->set_active (!yn);
2412 tact->set_active (yn);
2415 if ((prop = node.property ("show-editor-list"))) {
2417 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2420 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2421 bool yn = string_is_affirmative (prop->value());
2423 /* do it twice to force the change */
2425 tact->set_active (!yn);
2426 tact->set_active (yn);
2429 if ((prop = node.property (X_("editor-list-page")))) {
2430 _the_notebook.set_current_page (atoi (prop->value ()));
2433 if ((prop = node.property (X_("show-marker-lines")))) {
2434 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2436 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2437 bool yn = string_is_affirmative (prop->value ());
2439 tact->set_active (!yn);
2440 tact->set_active (yn);
2443 XMLNodeList children = node.children ();
2444 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2445 selection->set_state (**i, Stateful::current_state_version);
2446 _regions->set_state (**i);
2449 if ((prop = node.property ("maximised"))) {
2450 bool yn = string_is_affirmative (prop->value());
2452 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2456 if ((prop = node.property ("nudge-clock-value"))) {
2458 sscanf (prop->value().c_str(), "%" PRId64, &f);
2459 nudge_clock->set (f);
2461 nudge_clock->set_mode (AudioClock::Timecode);
2462 nudge_clock->set (_session->frame_rate() * 5, true);
2469 Editor::get_state ()
2471 XMLNode* node = new XMLNode ("Editor");
2474 id().print (buf, sizeof (buf));
2475 node->add_property ("id", buf);
2477 if (is_realized()) {
2478 Glib::RefPtr<Gdk::Window> win = get_window();
2480 int x, y, width, height;
2481 win->get_root_origin(x, y);
2482 win->get_size(width, height);
2484 XMLNode* geometry = new XMLNode ("geometry");
2486 snprintf(buf, sizeof(buf), "%d", width);
2487 geometry->add_property("x-size", string(buf));
2488 snprintf(buf, sizeof(buf), "%d", height);
2489 geometry->add_property("y-size", string(buf));
2490 snprintf(buf, sizeof(buf), "%d", x);
2491 geometry->add_property("x-pos", string(buf));
2492 snprintf(buf, sizeof(buf), "%d", y);
2493 geometry->add_property("y-pos", string(buf));
2494 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2495 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2496 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2497 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2498 geometry->add_property("edit-vertical-pane-pos", string(buf));
2500 node->add_child_nocopy (*geometry);
2503 maybe_add_mixer_strip_width (*node);
2505 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2506 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2507 node->add_property ("zoom", buf);
2508 node->add_property ("snap-to", enum_2_string (_snap_type));
2509 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2510 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2511 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2512 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2513 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2514 node->add_property ("edit-point", enum_2_string (_edit_point));
2516 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2517 node->add_property ("playhead", buf);
2518 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2519 node->add_property ("left-frame", buf);
2520 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2521 node->add_property ("y-origin", buf);
2523 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2524 node->add_property ("maximised", _maximised ? "yes" : "no");
2525 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2526 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2527 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2528 node->add_property ("mouse-mode", enum2str(mouse_mode));
2529 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2530 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2532 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2534 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2535 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2538 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2540 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2541 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2544 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2545 node->add_property (X_("editor-list-page"), buf);
2547 if (button_bindings) {
2548 XMLNode* bb = new XMLNode (X_("Buttons"));
2549 button_bindings->save (*bb);
2550 node->add_child_nocopy (*bb);
2553 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2555 node->add_child_nocopy (selection->get_state ());
2556 node->add_child_nocopy (_regions->get_state ());
2558 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2559 node->add_property ("nudge-clock-value", buf);
2566 /** @param y y offset from the top of all trackviews.
2567 * @return pair: TimeAxisView that y is over, layer index.
2568 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2569 * in stacked or expanded region display mode, otherwise 0.
2571 std::pair<TimeAxisView *, double>
2572 Editor::trackview_by_y_position (double y)
2574 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2576 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2582 return std::make_pair ( (TimeAxisView *) 0, 0);
2585 /** Snap a position to the grid, if appropriate, taking into account current
2586 * grid settings and also the state of any snap modifier keys that may be pressed.
2587 * @param start Position to snap.
2588 * @param event Event to get current key modifier information from, or 0.
2591 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2593 if (!_session || !event) {
2597 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2598 if (_snap_mode == SnapOff) {
2599 snap_to_internal (start, direction, for_mark);
2602 if (_snap_mode != SnapOff) {
2603 snap_to_internal (start, direction, for_mark);
2609 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2611 if (!_session || _snap_mode == SnapOff) {
2615 snap_to_internal (start, direction, for_mark);
2619 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2621 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2622 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2624 switch (_snap_type) {
2625 case SnapToTimecodeFrame:
2626 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2627 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2629 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2633 case SnapToTimecodeSeconds:
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start += _session->config.get_timecode_offset ();
2637 start -= _session->config.get_timecode_offset ();
2639 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2640 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2642 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2645 if (_session->config.get_timecode_offset_negative()) {
2646 start -= _session->config.get_timecode_offset ();
2648 start += _session->config.get_timecode_offset ();
2652 case SnapToTimecodeMinutes:
2653 if (_session->config.get_timecode_offset_negative()) {
2654 start += _session->config.get_timecode_offset ();
2656 start -= _session->config.get_timecode_offset ();
2658 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2659 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2661 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2663 if (_session->config.get_timecode_offset_negative()) {
2664 start -= _session->config.get_timecode_offset ();
2666 start += _session->config.get_timecode_offset ();
2670 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2676 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2678 const framepos_t one_second = _session->frame_rate();
2679 const framepos_t one_minute = _session->frame_rate() * 60;
2680 framepos_t presnap = start;
2684 switch (_snap_type) {
2685 case SnapToTimecodeFrame:
2686 case SnapToTimecodeSeconds:
2687 case SnapToTimecodeMinutes:
2688 return timecode_snap_to_internal (start, direction, for_mark);
2691 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2694 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2699 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2700 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2702 start = (framepos_t) floor ((double) start / one_second) * one_second;
2707 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2708 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2710 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2715 start = _session->tempo_map().round_to_bar (start, direction);
2719 start = _session->tempo_map().round_to_beat (start, direction);
2722 case SnapToBeatDiv128:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2725 case SnapToBeatDiv64:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2728 case SnapToBeatDiv32:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2731 case SnapToBeatDiv28:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2734 case SnapToBeatDiv24:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2737 case SnapToBeatDiv20:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2740 case SnapToBeatDiv16:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2743 case SnapToBeatDiv14:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2746 case SnapToBeatDiv12:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2749 case SnapToBeatDiv10:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2752 case SnapToBeatDiv8:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2755 case SnapToBeatDiv7:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2758 case SnapToBeatDiv6:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2761 case SnapToBeatDiv5:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2764 case SnapToBeatDiv4:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2767 case SnapToBeatDiv3:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2770 case SnapToBeatDiv2:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2779 _session->locations()->marks_either_side (start, before, after);
2781 if (before == max_framepos && after == max_framepos) {
2782 /* No marks to snap to, so just don't snap */
2784 } else if (before == max_framepos) {
2786 } else if (after == max_framepos) {
2788 } else if (before != max_framepos && after != max_framepos) {
2789 /* have before and after */
2790 if ((start - before) < (after - start)) {
2799 case SnapToRegionStart:
2800 case SnapToRegionEnd:
2801 case SnapToRegionSync:
2802 case SnapToRegionBoundary:
2803 if (!region_boundary_cache.empty()) {
2805 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2806 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2808 if (direction > 0) {
2809 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2811 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2814 if (next != region_boundary_cache.begin ()) {
2819 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2820 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2822 if (start > (p + n) / 2) {
2831 switch (_snap_mode) {
2837 if (presnap > start) {
2838 if (presnap > (start + unit_to_frame(snap_threshold))) {
2842 } else if (presnap < start) {
2843 if (presnap < (start - unit_to_frame(snap_threshold))) {
2849 /* handled at entry */
2857 Editor::setup_toolbar ()
2859 HBox* mode_box = manage(new HBox);
2860 mode_box->set_border_width (2);
2861 mode_box->set_spacing(4);
2863 HBox* mouse_mode_box = manage (new HBox);
2864 HBox* mouse_mode_hbox = manage (new HBox);
2865 VBox* mouse_mode_vbox = manage (new VBox);
2866 Alignment* mouse_mode_align = manage (new Alignment);
2868 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2869 // mouse_mode_size_group->add_widget (smart_mode_button);
2870 mouse_mode_size_group->add_widget (mouse_move_button);
2871 mouse_mode_size_group->add_widget (mouse_select_button);
2872 mouse_mode_size_group->add_widget (mouse_zoom_button);
2873 mouse_mode_size_group->add_widget (mouse_gain_button);
2874 mouse_mode_size_group->add_widget (mouse_timefx_button);
2875 mouse_mode_size_group->add_widget (mouse_audition_button);
2876 mouse_mode_size_group->add_widget (mouse_draw_button);
2877 mouse_mode_size_group->add_widget (internal_edit_button);
2879 /* make them just a bit bigger */
2880 mouse_move_button.set_size_request (-1, 30);
2882 mouse_mode_hbox->set_spacing (2);
2884 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2885 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2886 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2892 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2894 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2896 mouse_mode_align->add (*mouse_mode_vbox);
2897 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2899 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2901 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2902 if (!Profile->get_sae()) {
2903 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2905 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2907 edit_mode_selector.set_name ("EditModeSelector");
2908 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2909 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2911 mode_box->pack_start (edit_mode_selector, false, false);
2912 mode_box->pack_start (*mouse_mode_box, false, false);
2914 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2915 _mouse_mode_tearoff->set_name ("MouseModeBase");
2916 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2918 if (Profile->get_sae()) {
2919 _mouse_mode_tearoff->set_can_be_torn_off (false);
2922 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2923 &_mouse_mode_tearoff->tearoff_window()));
2924 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window(), 1));
2926 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window()));
2928 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window(), 1));
2933 _zoom_box.set_spacing (2);
2934 _zoom_box.set_border_width (2);
2938 zoom_in_button.set_name ("zoom button");
2939 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2940 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2941 zoom_in_button.set_image(::get_icon ("zoom_in"));
2942 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2943 zoom_in_button.set_related_action (act);
2945 zoom_out_button.set_name ("zoom button");
2946 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2947 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2948 zoom_out_button.set_image(::get_icon ("zoom_out"));
2949 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2950 zoom_out_button.set_related_action (act);
2952 zoom_out_full_button.set_name ("zoom button");
2953 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2954 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2955 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2956 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2957 zoom_out_full_button.set_related_action (act);
2959 zoom_focus_selector.set_name ("ZoomFocusSelector");
2960 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2961 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2963 _zoom_box.pack_start (zoom_out_button, false, false);
2964 _zoom_box.pack_start (zoom_in_button, false, false);
2965 _zoom_box.pack_start (zoom_out_full_button, false, false);
2967 _zoom_box.pack_start (zoom_focus_selector, false, false);
2969 /* Track zoom buttons */
2970 tav_expand_button.set_name ("zoom button");
2971 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2972 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2973 tav_expand_button.set_size_request (-1, 20);
2974 tav_expand_button.set_image(::get_icon ("tav_exp"));
2975 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2976 tav_expand_button.set_related_action (act);
2978 tav_shrink_button.set_name ("zoom button");
2979 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2980 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2981 tav_shrink_button.set_size_request (-1, 20);
2982 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2983 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2984 tav_shrink_button.set_related_action (act);
2986 _zoom_box.pack_start (tav_shrink_button);
2987 _zoom_box.pack_start (tav_expand_button);
2989 _zoom_tearoff = manage (new TearOff (_zoom_box));
2991 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2992 &_zoom_tearoff->tearoff_window()));
2993 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2994 &_zoom_tearoff->tearoff_window(), 0));
2995 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2996 &_zoom_tearoff->tearoff_window()));
2997 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2998 &_zoom_tearoff->tearoff_window(), 0));
3000 snap_box.set_spacing (2);
3001 snap_box.set_border_width (2);
3003 snap_type_selector.set_name ("SnapTypeSelector");
3004 set_popdown_strings (snap_type_selector, snap_type_strings);
3005 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3007 snap_mode_selector.set_name ("SnapModeSelector");
3008 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3009 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3011 edit_point_selector.set_name ("EditPointSelector");
3012 set_popdown_strings (edit_point_selector, edit_point_strings);
3013 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3015 snap_box.pack_start (snap_mode_selector, false, false);
3016 snap_box.pack_start (snap_type_selector, false, false);
3017 snap_box.pack_start (edit_point_selector, false, false);
3021 HBox *nudge_box = manage (new HBox);
3022 nudge_box->set_spacing (2);
3023 nudge_box->set_border_width (2);
3025 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3026 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3028 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3029 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3031 nudge_box->pack_start (nudge_backward_button, false, false);
3032 nudge_box->pack_start (nudge_forward_button, false, false);
3033 nudge_box->pack_start (*nudge_clock, false, false);
3036 /* Pack everything in... */
3038 HBox* hbox = manage (new HBox);
3039 hbox->set_spacing(10);
3041 _tools_tearoff = manage (new TearOff (*hbox));
3042 _tools_tearoff->set_name ("MouseModeBase");
3043 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3045 if (Profile->get_sae()) {
3046 _tools_tearoff->set_can_be_torn_off (false);
3049 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3050 &_tools_tearoff->tearoff_window()));
3051 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3052 &_tools_tearoff->tearoff_window(), 0));
3053 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3054 &_tools_tearoff->tearoff_window()));
3055 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3056 &_tools_tearoff->tearoff_window(), 0));
3058 toolbar_hbox.set_spacing (10);
3059 toolbar_hbox.set_border_width (1);
3061 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3062 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3063 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3065 hbox->pack_start (snap_box, false, false);
3066 if (!Profile->get_small_screen()) {
3067 hbox->pack_start (*nudge_box, false, false);
3069 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3071 hbox->pack_start (panic_box, false, false);
3075 toolbar_base.set_name ("ToolBarBase");
3076 toolbar_base.add (toolbar_hbox);
3078 _toolbar_viewport.add (toolbar_base);
3079 /* stick to the required height but allow width to vary if there's not enough room */
3080 _toolbar_viewport.set_size_request (1, -1);
3082 toolbar_frame.set_shadow_type (SHADOW_OUT);
3083 toolbar_frame.set_name ("BaseFrame");
3084 toolbar_frame.add (_toolbar_viewport);
3088 Editor::setup_tooltips ()
3090 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3091 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3092 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3093 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3094 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3095 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3096 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3097 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3098 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3099 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3100 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3101 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3102 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3103 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3104 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3105 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3106 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3107 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3108 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3109 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3110 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3111 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3112 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3116 Editor::convert_drop_to_paths (
3117 vector<string>& paths,
3118 const RefPtr<Gdk::DragContext>& /*context*/,
3121 const SelectionData& data,
3125 if (_session == 0) {
3129 vector<string> uris = data.get_uris();
3133 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3134 are actually URI lists. So do it by hand.
3137 if (data.get_target() != "text/plain") {
3141 /* Parse the "uri-list" format that Nautilus provides,
3142 where each pathname is delimited by \r\n.
3144 THERE MAY BE NO NULL TERMINATING CHAR!!!
3147 string txt = data.get_text();
3151 p = (const char *) malloc (txt.length() + 1);
3152 txt.copy (const_cast<char *> (p), txt.length(), 0);
3153 const_cast<char*>(p)[txt.length()] = '\0';
3159 while (g_ascii_isspace (*p))
3163 while (*q && (*q != '\n') && (*q != '\r')) {
3170 while (q > p && g_ascii_isspace (*q))
3175 uris.push_back (string (p, q - p + 1));
3179 p = strchr (p, '\n');
3191 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3193 if ((*i).substr (0,7) == "file://") {
3195 string const p = PBD::url_decode (*i);
3197 // scan forward past three slashes
3199 string::size_type slashcnt = 0;
3200 string::size_type n = 0;
3201 string::const_iterator x = p.begin();
3203 while (slashcnt < 3 && x != p.end()) {
3206 } else if (slashcnt == 3) {
3213 if (slashcnt != 3 || x == p.end()) {
3214 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3218 paths.push_back (p.substr (n - 1));
3226 Editor::new_tempo_section ()
3232 Editor::map_transport_state ()
3234 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3236 if (_session && _session->transport_stopped()) {
3237 have_pending_keyboard_selection = false;
3240 update_loop_range_view (true);
3246 Editor::begin_reversible_command (string name)
3249 _session->begin_reversible_command (name);
3254 Editor::begin_reversible_command (GQuark q)
3257 _session->begin_reversible_command (q);
3262 Editor::commit_reversible_command ()
3265 _session->commit_reversible_command ();
3270 Editor::history_changed ()
3274 if (undo_action && _session) {
3275 if (_session->undo_depth() == 0) {
3276 label = S_("Command|Undo");
3278 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3280 undo_action->property_label() = label;
3283 if (redo_action && _session) {
3284 if (_session->redo_depth() == 0) {
3287 label = string_compose(_("Redo (%1)"), _session->next_redo());
3289 redo_action->property_label() = label;
3294 Editor::duplicate_range (bool with_dialog)
3298 RegionSelection rs = get_regions_from_selection_and_entered ();
3300 if ( selection->time.length() == 0 && rs.empty()) {
3306 ArdourDialog win (_("Duplicate"));
3307 Label label (_("Number of duplications:"));
3308 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3309 SpinButton spinner (adjustment, 0.0, 1);
3312 win.get_vbox()->set_spacing (12);
3313 win.get_vbox()->pack_start (hbox);
3314 hbox.set_border_width (6);
3315 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3317 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3318 place, visually. so do this by hand.
3321 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3322 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3323 spinner.grab_focus();
3329 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3330 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3331 win.set_default_response (RESPONSE_ACCEPT);
3333 win.set_position (WIN_POS_MOUSE);
3335 spinner.grab_focus ();
3337 switch (win.run ()) {
3338 case RESPONSE_ACCEPT:
3344 times = adjustment.get_value();
3347 if ((current_mouse_mode() == Editing::MouseRange)) {
3348 if (selection->time.length()) {
3349 duplicate_selection (times);
3351 } else if (get_smart_mode()) {
3352 if (selection->time.length()) {
3353 duplicate_selection (times);
3355 duplicate_some_regions (rs, times);
3357 duplicate_some_regions (rs, times);
3362 Editor::set_edit_mode (EditMode m)
3364 Config->set_edit_mode (m);
3368 Editor::cycle_edit_mode ()
3370 switch (Config->get_edit_mode()) {
3372 if (Profile->get_sae()) {
3373 Config->set_edit_mode (Lock);
3375 Config->set_edit_mode (Splice);
3379 Config->set_edit_mode (Lock);
3382 Config->set_edit_mode (Slide);
3388 Editor::edit_mode_selection_done ()
3390 string s = edit_mode_selector.get_active_text ();
3393 Config->set_edit_mode (string_to_edit_mode (s));
3398 Editor::snap_type_selection_done ()
3400 string choice = snap_type_selector.get_active_text();
3401 SnapType snaptype = SnapToBeat;
3403 if (choice == _("Beats/2")) {
3404 snaptype = SnapToBeatDiv2;
3405 } else if (choice == _("Beats/3")) {
3406 snaptype = SnapToBeatDiv3;
3407 } else if (choice == _("Beats/4")) {
3408 snaptype = SnapToBeatDiv4;
3409 } else if (choice == _("Beats/5")) {
3410 snaptype = SnapToBeatDiv5;
3411 } else if (choice == _("Beats/6")) {
3412 snaptype = SnapToBeatDiv6;
3413 } else if (choice == _("Beats/7")) {
3414 snaptype = SnapToBeatDiv7;
3415 } else if (choice == _("Beats/8")) {
3416 snaptype = SnapToBeatDiv8;
3417 } else if (choice == _("Beats/10")) {
3418 snaptype = SnapToBeatDiv10;
3419 } else if (choice == _("Beats/12")) {
3420 snaptype = SnapToBeatDiv12;
3421 } else if (choice == _("Beats/14")) {
3422 snaptype = SnapToBeatDiv14;
3423 } else if (choice == _("Beats/16")) {
3424 snaptype = SnapToBeatDiv16;
3425 } else if (choice == _("Beats/20")) {
3426 snaptype = SnapToBeatDiv20;
3427 } else if (choice == _("Beats/24")) {
3428 snaptype = SnapToBeatDiv24;
3429 } else if (choice == _("Beats/28")) {
3430 snaptype = SnapToBeatDiv28;
3431 } else if (choice == _("Beats/32")) {
3432 snaptype = SnapToBeatDiv32;
3433 } else if (choice == _("Beats/64")) {
3434 snaptype = SnapToBeatDiv64;
3435 } else if (choice == _("Beats/128")) {
3436 snaptype = SnapToBeatDiv128;
3437 } else if (choice == _("Beats")) {
3438 snaptype = SnapToBeat;
3439 } else if (choice == _("Bars")) {
3440 snaptype = SnapToBar;
3441 } else if (choice == _("Marks")) {
3442 snaptype = SnapToMark;
3443 } else if (choice == _("Region starts")) {
3444 snaptype = SnapToRegionStart;
3445 } else if (choice == _("Region ends")) {
3446 snaptype = SnapToRegionEnd;
3447 } else if (choice == _("Region bounds")) {
3448 snaptype = SnapToRegionBoundary;
3449 } else if (choice == _("Region syncs")) {
3450 snaptype = SnapToRegionSync;
3451 } else if (choice == _("CD Frames")) {
3452 snaptype = SnapToCDFrame;
3453 } else if (choice == _("Timecode Frames")) {
3454 snaptype = SnapToTimecodeFrame;
3455 } else if (choice == _("Timecode Seconds")) {
3456 snaptype = SnapToTimecodeSeconds;
3457 } else if (choice == _("Timecode Minutes")) {
3458 snaptype = SnapToTimecodeMinutes;
3459 } else if (choice == _("Seconds")) {
3460 snaptype = SnapToSeconds;
3461 } else if (choice == _("Minutes")) {
3462 snaptype = SnapToMinutes;
3465 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3467 ract->set_active ();
3472 Editor::snap_mode_selection_done ()
3474 string choice = snap_mode_selector.get_active_text();
3475 SnapMode mode = SnapNormal;
3477 if (choice == _("No Grid")) {
3479 } else if (choice == _("Grid")) {
3481 } else if (choice == _("Magnetic")) {
3482 mode = SnapMagnetic;
3485 RefPtr<RadioAction> ract = snap_mode_action (mode);
3488 ract->set_active (true);
3493 Editor::cycle_edit_point (bool with_marker)
3495 switch (_edit_point) {
3497 set_edit_point_preference (EditAtPlayhead);
3499 case EditAtPlayhead:
3501 set_edit_point_preference (EditAtSelectedMarker);
3503 set_edit_point_preference (EditAtMouse);
3506 case EditAtSelectedMarker:
3507 set_edit_point_preference (EditAtMouse);
3513 Editor::edit_point_selection_done ()
3515 string choice = edit_point_selector.get_active_text();
3516 EditPoint ep = EditAtSelectedMarker;
3518 if (choice == _("Marker")) {
3519 set_edit_point_preference (EditAtSelectedMarker);
3520 } else if (choice == _("Playhead")) {
3521 set_edit_point_preference (EditAtPlayhead);
3523 set_edit_point_preference (EditAtMouse);
3526 RefPtr<RadioAction> ract = edit_point_action (ep);
3529 ract->set_active (true);
3534 Editor::zoom_focus_selection_done ()
3536 string choice = zoom_focus_selector.get_active_text();
3537 ZoomFocus focus_type = ZoomFocusLeft;
3539 if (choice == _("Left")) {
3540 focus_type = ZoomFocusLeft;
3541 } else if (choice == _("Right")) {
3542 focus_type = ZoomFocusRight;
3543 } else if (choice == _("Center")) {
3544 focus_type = ZoomFocusCenter;
3545 } else if (choice == _("Playhead")) {
3546 focus_type = ZoomFocusPlayhead;
3547 } else if (choice == _("Mouse")) {
3548 focus_type = ZoomFocusMouse;
3549 } else if (choice == _("Edit point")) {
3550 focus_type = ZoomFocusEdit;
3553 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3556 ract->set_active ();
3561 Editor::edit_controls_button_release (GdkEventButton* ev)
3563 if (Keyboard::is_context_menu_event (ev)) {
3564 ARDOUR_UI::instance()->add_route (this);
3565 } else if (ev->button == 1) {
3566 selection->clear_tracks ();
3573 Editor::mouse_select_button_release (GdkEventButton* ev)
3575 /* this handles just right-clicks */
3577 if (ev->button != 3) {
3585 Editor::set_zoom_focus (ZoomFocus f)
3587 string str = zoom_focus_strings[(int)f];
3589 if (str != zoom_focus_selector.get_active_text()) {
3590 zoom_focus_selector.set_active_text (str);
3593 if (zoom_focus != f) {
3600 Editor::cycle_zoom_focus ()
3602 switch (zoom_focus) {
3604 set_zoom_focus (ZoomFocusRight);
3606 case ZoomFocusRight:
3607 set_zoom_focus (ZoomFocusCenter);
3609 case ZoomFocusCenter:
3610 set_zoom_focus (ZoomFocusPlayhead);
3612 case ZoomFocusPlayhead:
3613 set_zoom_focus (ZoomFocusMouse);
3615 case ZoomFocusMouse:
3616 set_zoom_focus (ZoomFocusEdit);
3619 set_zoom_focus (ZoomFocusLeft);
3625 Editor::ensure_float (Window& win)
3627 win.set_transient_for (*this);
3631 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3633 /* recover or initialize pane positions. do this here rather than earlier because
3634 we don't want the positions to change the child allocations, which they seem to do.
3640 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3649 XMLNode* geometry = find_named_node (*node, "geometry");
3651 if (which == static_cast<Paned*> (&edit_pane)) {
3653 if (done & Horizontal) {
3657 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3658 _notebook_shrunk = string_is_affirmative (prop->value ());
3661 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3662 /* initial allocation is 90% to canvas, 10% to notebook */
3663 pos = (int) floor (alloc.get_width() * 0.90f);
3664 snprintf (buf, sizeof(buf), "%d", pos);
3666 pos = atoi (prop->value());
3669 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3670 edit_pane.set_position (pos);
3673 done = (Pane) (done | Horizontal);
3675 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3677 if (done & Vertical) {
3681 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3682 /* initial allocation is 90% to canvas, 10% to summary */
3683 pos = (int) floor (alloc.get_height() * 0.90f);
3684 snprintf (buf, sizeof(buf), "%d", pos);
3687 pos = atoi (prop->value());
3690 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3691 editor_summary_pane.set_position (pos);
3694 done = (Pane) (done | Vertical);
3699 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3701 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3702 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3703 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3704 top_hbox.remove (toolbar_frame);
3709 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3711 if (toolbar_frame.get_parent() == 0) {
3712 top_hbox.pack_end (toolbar_frame);
3717 Editor::set_show_measures (bool yn)
3719 if (_show_measures != yn) {
3722 if ((_show_measures = yn) == true) {
3724 tempo_lines->show();
3726 (void) redraw_measures ();
3733 Editor::toggle_follow_playhead ()
3735 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3737 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3738 set_follow_playhead (tact->get_active());
3742 /** @param yn true to follow playhead, otherwise false.
3743 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3746 Editor::set_follow_playhead (bool yn, bool catch_up)
3748 if (_follow_playhead != yn) {
3749 if ((_follow_playhead = yn) == true && catch_up) {
3751 reset_x_origin_to_follow_playhead ();
3758 Editor::toggle_stationary_playhead ()
3760 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3762 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3763 set_stationary_playhead (tact->get_active());
3768 Editor::set_stationary_playhead (bool yn)
3770 if (_stationary_playhead != yn) {
3771 if ((_stationary_playhead = yn) == true) {
3773 // FIXME need a 3.0 equivalent of this 2.X call
3774 // update_current_screen ();
3781 Editor::playlist_selector () const
3783 return *_playlist_selector;
3787 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3791 switch (_snap_type) {
3796 case SnapToBeatDiv128:
3799 case SnapToBeatDiv64:
3802 case SnapToBeatDiv32:
3805 case SnapToBeatDiv28:
3808 case SnapToBeatDiv24:
3811 case SnapToBeatDiv20:
3814 case SnapToBeatDiv16:
3817 case SnapToBeatDiv14:
3820 case SnapToBeatDiv12:
3823 case SnapToBeatDiv10:
3826 case SnapToBeatDiv8:
3829 case SnapToBeatDiv7:
3832 case SnapToBeatDiv6:
3835 case SnapToBeatDiv5:
3838 case SnapToBeatDiv4:
3841 case SnapToBeatDiv3:
3844 case SnapToBeatDiv2:
3850 return _session->tempo_map().meter_at (position).divisions_per_bar();
3855 case SnapToTimecodeFrame:
3856 case SnapToTimecodeSeconds:
3857 case SnapToTimecodeMinutes:
3860 case SnapToRegionStart:
3861 case SnapToRegionEnd:
3862 case SnapToRegionSync:
3863 case SnapToRegionBoundary:
3873 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3877 ret = nudge_clock->current_duration (pos);
3878 next = ret + 1; /* XXXX fix me */
3884 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3886 ArdourDialog dialog (_("Playlist Deletion"));
3887 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3888 "If it is kept, its audio files will not be cleaned.\n"
3889 "If it is deleted, audio files used by it alone will be cleaned."),
3892 dialog.set_position (WIN_POS_CENTER);
3893 dialog.get_vbox()->pack_start (label);
3897 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3898 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3899 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3901 switch (dialog.run ()) {
3902 case RESPONSE_ACCEPT:
3903 /* delete the playlist */
3907 case RESPONSE_REJECT:
3908 /* keep the playlist */
3920 Editor::audio_region_selection_covers (framepos_t where)
3922 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3923 if ((*a)->region()->covers (where)) {
3932 Editor::prepare_for_cleanup ()
3934 cut_buffer->clear_regions ();
3935 cut_buffer->clear_playlists ();
3937 selection->clear_regions ();
3938 selection->clear_playlists ();
3940 _regions->suspend_redisplay ();
3944 Editor::finish_cleanup ()
3946 _regions->resume_redisplay ();
3950 Editor::transport_loop_location()
3953 return _session->locations()->auto_loop_location();
3960 Editor::transport_punch_location()
3963 return _session->locations()->auto_punch_location();
3970 Editor::control_layout_scroll (GdkEventScroll* ev)
3972 if (Keyboard::some_magic_widget_has_focus()) {
3976 switch (ev->direction) {
3978 scroll_tracks_up_line ();
3982 case GDK_SCROLL_DOWN:
3983 scroll_tracks_down_line ();
3987 /* no left/right handling yet */
3995 Editor::session_state_saved (string)
3998 _snapshots->redisplay ();
4002 Editor::update_tearoff_visibility()
4004 bool visible = Config->get_keep_tearoffs();
4005 _mouse_mode_tearoff->set_visible (visible);
4006 _tools_tearoff->set_visible (visible);
4007 _zoom_tearoff->set_visible (visible);
4011 Editor::maximise_editing_space ()
4023 Editor::restore_editing_space ()
4035 * Make new playlists for a given track and also any others that belong
4036 * to the same active route group with the `select' property.
4041 Editor::new_playlists (TimeAxisView* v)
4043 begin_reversible_command (_("new playlists"));
4044 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4045 _session->playlists->get (playlists);
4046 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4047 commit_reversible_command ();
4051 * Use a copy of the current playlist for a given track and also any others that belong
4052 * to the same active route group with the `select' property.
4057 Editor::copy_playlists (TimeAxisView* v)
4059 begin_reversible_command (_("copy playlists"));
4060 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4061 _session->playlists->get (playlists);
4062 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4063 commit_reversible_command ();
4066 /** Clear the current playlist for a given track and also any others that belong
4067 * to the same active route group with the `select' property.
4072 Editor::clear_playlists (TimeAxisView* v)
4074 begin_reversible_command (_("clear playlists"));
4075 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4076 _session->playlists->get (playlists);
4077 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4078 commit_reversible_command ();
4082 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4084 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4088 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4090 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4094 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4096 atv.clear_playlist ();
4100 Editor::on_key_press_event (GdkEventKey* ev)
4102 return key_press_focus_accelerator_handler (*this, ev);
4106 Editor::on_key_release_event (GdkEventKey* ev)
4108 return Gtk::Window::on_key_release_event (ev);
4109 // return key_press_focus_accelerator_handler (*this, ev);
4112 /** Queue up a change to the viewport x origin.
4113 * @param frame New x origin.
4116 Editor::reset_x_origin (framepos_t frame)
4118 pending_visual_change.add (VisualChange::TimeOrigin);
4119 pending_visual_change.time_origin = frame;
4120 ensure_visual_change_idle_handler ();
4124 Editor::reset_y_origin (double y)
4126 pending_visual_change.add (VisualChange::YOrigin);
4127 pending_visual_change.y_origin = y;
4128 ensure_visual_change_idle_handler ();
4132 Editor::reset_zoom (double fpu)
4134 clamp_frames_per_unit (fpu);
4136 if (fpu == frames_per_unit) {
4140 pending_visual_change.add (VisualChange::ZoomLevel);
4141 pending_visual_change.frames_per_unit = fpu;
4142 ensure_visual_change_idle_handler ();
4146 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4148 reset_x_origin (frame);
4151 if (!no_save_visual) {
4152 undo_visual_stack.push_back (current_visual_state(false));
4156 Editor::VisualState::VisualState (bool with_tracks)
4157 : gui_state (with_tracks ? new GUIObjectState : 0)
4161 Editor::VisualState::~VisualState ()
4166 Editor::VisualState*
4167 Editor::current_visual_state (bool with_tracks)
4169 VisualState* vs = new VisualState (with_tracks);
4170 vs->y_position = vertical_adjustment.get_value();
4171 vs->frames_per_unit = frames_per_unit;
4172 vs->leftmost_frame = leftmost_frame;
4173 vs->zoom_focus = zoom_focus;
4176 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4183 Editor::undo_visual_state ()
4185 if (undo_visual_stack.empty()) {
4189 VisualState* vs = undo_visual_stack.back();
4190 undo_visual_stack.pop_back();
4193 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4195 use_visual_state (*vs);
4199 Editor::redo_visual_state ()
4201 if (redo_visual_stack.empty()) {
4205 VisualState* vs = redo_visual_stack.back();
4206 redo_visual_stack.pop_back();
4208 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4210 use_visual_state (*vs);
4214 Editor::swap_visual_state ()
4216 if (undo_visual_stack.empty()) {
4217 redo_visual_state ();
4219 undo_visual_state ();
4224 Editor::use_visual_state (VisualState& vs)
4226 PBD::Unwinder<bool> nsv (no_save_visual, true);
4228 _routes->suspend_redisplay ();
4230 vertical_adjustment.set_value (vs.y_position);
4232 set_zoom_focus (vs.zoom_focus);
4233 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4236 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4238 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4239 (*i)->reset_visual_state ();
4243 _routes->update_visibility ();
4244 _routes->resume_redisplay ();
4247 /** This is the core function that controls the zoom level of the canvas. It is called
4248 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4249 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4252 Editor::set_frames_per_unit (double fpu)
4255 tempo_lines->tempo_map_changed();
4258 frames_per_unit = fpu;
4260 /* convert fpu to frame count */
4262 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4264 if (frames_per_unit != zoom_range_clock->current_duration()) {
4265 zoom_range_clock->set (frames);
4268 bool const showing_time_selection = selection->time.length() > 0;
4270 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4271 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4272 (*i)->reshow_selection (selection->time);
4276 ZoomChanged (); /* EMIT_SIGNAL */
4278 //reset_scrolling_region ();
4280 if (playhead_cursor) {
4281 playhead_cursor->set_position (playhead_cursor->current_frame);
4284 refresh_location_display();
4285 _summary->set_overlays_dirty ();
4287 update_marker_labels ();
4293 Editor::queue_visual_videotimeline_update ()
4296 * pending_visual_change.add (VisualChange::VideoTimeline);
4297 * or maybe even more specific: which videotimeline-image
4298 * currently it calls update_video_timeline() to update
4299 * _all outdated_ images on the video-timeline.
4300 * see 'exposeimg()' in video_image_frame.cc
4302 ensure_visual_change_idle_handler ();
4306 Editor::ensure_visual_change_idle_handler ()
4308 if (pending_visual_change.idle_handler_id < 0) {
4309 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4314 Editor::_idle_visual_changer (void* arg)
4316 return static_cast<Editor*>(arg)->idle_visual_changer ();
4320 Editor::idle_visual_changer ()
4322 /* set_horizontal_position() below (and maybe other calls) call
4323 gtk_main_iteration(), so it's possible that a signal will be handled
4324 half-way through this method. If this signal wants an
4325 idle_visual_changer we must schedule another one after this one, so
4326 mark the idle_handler_id as -1 here to allow that. Also make a note
4327 that we are doing the visual change, so that changes in response to
4328 super-rapid-screen-update can be dropped if we are still processing
4332 pending_visual_change.idle_handler_id = -1;
4333 pending_visual_change.being_handled = true;
4335 VisualChange::Type p = pending_visual_change.pending;
4336 pending_visual_change.pending = (VisualChange::Type) 0;
4338 double const last_time_origin = horizontal_position ();
4340 if (p & VisualChange::ZoomLevel) {
4341 set_frames_per_unit (pending_visual_change.frames_per_unit);
4343 compute_fixed_ruler_scale ();
4345 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4346 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4348 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4349 current_bbt_points_begin, current_bbt_points_end);
4350 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4351 current_bbt_points_begin, current_bbt_points_end);
4352 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4355 if (p & VisualChange::ZoomLevel) {
4356 update_video_timeline();
4359 if (p & VisualChange::TimeOrigin) {
4360 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4363 if (p & VisualChange::YOrigin) {
4364 vertical_adjustment.set_value (pending_visual_change.y_origin);
4367 if (last_time_origin == horizontal_position ()) {
4368 /* changed signal not emitted */
4369 update_fixed_rulers ();
4370 redisplay_tempo (true);
4373 if (!(p & VisualChange::ZoomLevel)) {
4374 update_video_timeline();
4377 _summary->set_overlays_dirty ();
4379 pending_visual_change.being_handled = false;
4380 return 0; /* this is always a one-shot call */
4383 struct EditorOrderTimeAxisSorter {
4384 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4385 return a->order () < b->order ();
4390 Editor::sort_track_selection (TrackViewList& sel)
4392 EditorOrderTimeAxisSorter cmp;
4397 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4400 framepos_t where = 0;
4401 EditPoint ep = _edit_point;
4403 if (from_context_menu && (ep == EditAtMouse)) {
4404 return event_frame (&context_click_event, 0, 0);
4407 if (entered_marker) {
4408 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4409 return entered_marker->position();
4412 if (ignore_playhead && ep == EditAtPlayhead) {
4413 ep = EditAtSelectedMarker;
4417 case EditAtPlayhead:
4418 where = _session->audible_frame();
4419 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4422 case EditAtSelectedMarker:
4423 if (!selection->markers.empty()) {
4425 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4428 where = loc->start();
4432 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4440 if (!mouse_frame (where, ignored)) {
4441 /* XXX not right but what can we do ? */
4445 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4453 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4455 if (!_session) return;
4457 begin_reversible_command (cmd);
4461 if ((tll = transport_loop_location()) == 0) {
4462 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4463 XMLNode &before = _session->locations()->get_state();
4464 _session->locations()->add (loc, true);
4465 _session->set_auto_loop_location (loc);
4466 XMLNode &after = _session->locations()->get_state();
4467 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4469 XMLNode &before = tll->get_state();
4470 tll->set_hidden (false, this);
4471 tll->set (start, end);
4472 XMLNode &after = tll->get_state();
4473 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4476 commit_reversible_command ();
4480 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4482 if (!_session) return;
4484 begin_reversible_command (cmd);
4488 if ((tpl = transport_punch_location()) == 0) {
4489 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4490 XMLNode &before = _session->locations()->get_state();
4491 _session->locations()->add (loc, true);
4492 _session->set_auto_loop_location (loc);
4493 XMLNode &after = _session->locations()->get_state();
4494 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4497 XMLNode &before = tpl->get_state();
4498 tpl->set_hidden (false, this);
4499 tpl->set (start, end);
4500 XMLNode &after = tpl->get_state();
4501 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4504 commit_reversible_command ();
4507 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4508 * @param rs List to which found regions are added.
4509 * @param where Time to look at.
4510 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4513 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4515 const TrackViewList* tracks;
4518 tracks = &track_views;
4523 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4525 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4528 boost::shared_ptr<Track> tr;
4529 boost::shared_ptr<Playlist> pl;
4531 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4533 boost::shared_ptr<RegionList> regions = pl->regions_at (
4534 (framepos_t) floor ( (double) where * tr->speed()));
4536 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4537 RegionView* rv = rtv->view()->find_view (*i);
4548 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4550 const TrackViewList* tracks;
4553 tracks = &track_views;
4558 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4559 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4561 boost::shared_ptr<Track> tr;
4562 boost::shared_ptr<Playlist> pl;
4564 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4566 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4567 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4569 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4571 RegionView* rv = rtv->view()->find_view (*i);
4582 /** Get regions using the following method:
4584 * Make a region list using the selected regions, unless
4585 * the edit point is `mouse' and the mouse is over an unselected
4586 * region. In this case, use just that region.
4588 * If the edit point is not 'mouse', and there are no regions selected,
4589 * search the list of selected tracks and return regions that are under
4590 * the edit point on these tracks. If there are no selected tracks and
4591 * 'No Selection = All Tracks' is active, search all tracks,
4593 * The rationale here is that the mouse edit point is special in that
4594 * its position describes both a time and a track; the other edit
4595 * modes only describe a time. Hence if the edit point is `mouse' we
4596 * ignore selected tracks, as we assume the user means something by
4597 * pointing at a particular track. Also in this case we take note of
4598 * the region directly under the edit point, as there is always just one
4599 * (rather than possibly several with non-mouse edit points).
4603 Editor::get_regions_from_selection_and_edit_point ()
4605 RegionSelection regions;
4607 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4608 regions.add (entered_regionview);
4610 regions = selection->regions;
4614 if (regions.empty() && _edit_point != EditAtMouse) {
4615 TrackViewList tracks = selection->tracks;
4617 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4618 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4619 * is enabled, so consider all tracks
4621 tracks = track_views;
4624 if (!tracks.empty()) {
4625 /* no region selected or entered, but some selected tracks:
4626 * act on all regions on the selected tracks at the edit point
4628 framepos_t const where = get_preferred_edit_position ();
4629 get_regions_at(regions, where, tracks);
4635 /** Start with regions that are selected, or the entered regionview if none are selected.
4636 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4637 * of the regions that we started with.
4641 Editor::get_regions_from_selection_and_entered ()
4643 RegionSelection regions = selection->regions;
4645 if (regions.empty() && entered_regionview) {
4646 regions.add (entered_regionview);
4653 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4655 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4657 RouteTimeAxisView* tatv;
4659 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4661 boost::shared_ptr<Playlist> pl;
4662 vector<boost::shared_ptr<Region> > results;
4664 boost::shared_ptr<Track> tr;
4666 if ((tr = tatv->track()) == 0) {
4671 if ((pl = (tr->playlist())) != 0) {
4672 if (src_comparison) {
4673 pl->get_source_equivalent_regions (region, results);
4675 pl->get_region_list_equivalent_regions (region, results);
4679 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4680 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4681 regions.push_back (marv);
4690 Editor::show_rhythm_ferret ()
4692 if (rhythm_ferret == 0) {
4693 rhythm_ferret = new RhythmFerret(*this);
4696 rhythm_ferret->set_session (_session);
4697 rhythm_ferret->show ();
4698 rhythm_ferret->present ();
4702 Editor::first_idle ()
4704 MessageDialog* dialog = 0;
4706 if (track_views.size() > 1) {
4707 dialog = new MessageDialog (
4709 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4713 ARDOUR_UI::instance()->flush_pending ();
4716 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4720 // first idle adds route children (automation tracks), so we need to redisplay here
4721 _routes->redisplay ();
4728 Editor::_idle_resize (gpointer arg)
4730 return ((Editor*)arg)->idle_resize ();
4734 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4736 if (resize_idle_id < 0) {
4737 resize_idle_id = g_idle_add (_idle_resize, this);
4738 _pending_resize_amount = 0;
4741 /* make a note of the smallest resulting height, so that we can clamp the
4742 lower limit at TimeAxisView::hSmall */
4744 int32_t min_resulting = INT32_MAX;
4746 _pending_resize_amount += h;
4747 _pending_resize_view = view;
4749 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4751 if (selection->tracks.contains (_pending_resize_view)) {
4752 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4753 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4757 if (min_resulting < 0) {
4762 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4763 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4767 /** Handle pending resizing of tracks */
4769 Editor::idle_resize ()
4771 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4773 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4774 selection->tracks.contains (_pending_resize_view)) {
4776 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4777 if (*i != _pending_resize_view) {
4778 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4783 _pending_resize_amount = 0;
4785 _group_tabs->set_dirty ();
4786 resize_idle_id = -1;
4794 ENSURE_GUI_THREAD (*this, &Editor::located);
4797 playhead_cursor->set_position (_session->audible_frame ());
4798 if (_follow_playhead && !_pending_initial_locate) {
4799 reset_x_origin_to_follow_playhead ();
4803 _pending_locate_request = false;
4804 _pending_initial_locate = false;
4808 Editor::region_view_added (RegionView *)
4810 _summary->set_dirty ();
4814 Editor::region_view_removed ()
4816 _summary->set_dirty ();
4820 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4822 TrackViewList::const_iterator j = track_views.begin ();
4823 while (j != track_views.end()) {
4824 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4825 if (rtv && rtv->route() == r) {
4836 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4840 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4841 TimeAxisView* tv = axis_view_from_route (*i);
4851 Editor::add_routes (RouteList& routes)
4853 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4855 RouteTimeAxisView *rtv;
4856 list<RouteTimeAxisView*> new_views;
4858 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4859 boost::shared_ptr<Route> route = (*x);
4861 if (route->is_auditioner() || route->is_monitor()) {
4865 DataType dt = route->input()->default_type();
4867 if (dt == ARDOUR::DataType::AUDIO) {
4868 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4869 rtv->set_route (route);
4870 } else if (dt == ARDOUR::DataType::MIDI) {
4871 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4872 rtv->set_route (route);
4874 throw unknown_type();
4877 new_views.push_back (rtv);
4878 track_views.push_back (rtv);
4880 rtv->effective_gain_display ();
4882 if (internal_editing()) {
4883 rtv->enter_internal_edit_mode ();
4885 rtv->leave_internal_edit_mode ();
4888 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4889 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4892 _routes->routes_added (new_views);
4893 _summary->routes_added (new_views);
4895 if (show_editor_mixer_when_tracks_arrive) {
4896 show_editor_mixer (true);
4899 editor_list_button.set_sensitive (true);
4903 Editor::timeaxisview_deleted (TimeAxisView *tv)
4905 if (_session && _session->deletion_in_progress()) {
4906 /* the situation is under control */
4910 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4912 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4914 _routes->route_removed (tv);
4916 if (tv == entered_track) {
4920 TimeAxisView::Children c = tv->get_child_list ();
4921 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4922 if (entered_track == i->get()) {
4927 /* remove it from the list of track views */
4929 TrackViewList::iterator i;
4931 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4932 i = track_views.erase (i);
4935 /* update whatever the current mixer strip is displaying, if revelant */
4937 boost::shared_ptr<Route> route;
4940 route = rtav->route ();
4943 if (current_mixer_strip && current_mixer_strip->route() == route) {
4945 TimeAxisView* next_tv;
4947 if (track_views.empty()) {
4949 } else if (i == track_views.end()) {
4950 next_tv = track_views.front();
4957 set_selected_mixer_strip (*next_tv);
4959 /* make the editor mixer strip go away setting the
4960 * button to inactive (which also unticks the menu option)
4963 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4969 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4971 if (apply_to_selection) {
4972 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4974 TrackSelection::iterator j = i;
4977 hide_track_in_display (*i, false);
4982 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4984 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4985 // this will hide the mixer strip
4986 set_selected_mixer_strip (*tv);
4989 _routes->hide_track_in_display (*tv);
4994 Editor::sync_track_view_list_and_routes ()
4996 track_views = TrackViewList (_routes->views ());
4998 _summary->set_dirty ();
4999 _group_tabs->set_dirty ();
5001 return false; // do not call again (until needed)
5005 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5007 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5012 /** Find a RouteTimeAxisView by the ID of its route */
5014 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5016 RouteTimeAxisView* v;
5018 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5019 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5020 if(v->route()->id() == id) {
5030 Editor::fit_route_group (RouteGroup *g)
5032 TrackViewList ts = axis_views_from_routes (g->route_list ());
5037 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5039 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5042 _session->cancel_audition ();
5046 if (_session->is_auditioning()) {
5047 _session->cancel_audition ();
5048 if (r == last_audition_region) {
5053 _session->audition_region (r);
5054 last_audition_region = r;
5059 Editor::hide_a_region (boost::shared_ptr<Region> r)
5061 r->set_hidden (true);
5065 Editor::show_a_region (boost::shared_ptr<Region> r)
5067 r->set_hidden (false);
5071 Editor::audition_region_from_region_list ()
5073 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5077 Editor::hide_region_from_region_list ()
5079 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5083 Editor::show_region_in_region_list ()
5085 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5089 Editor::step_edit_status_change (bool yn)
5092 start_step_editing ();
5094 stop_step_editing ();
5099 Editor::start_step_editing ()
5101 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5105 Editor::stop_step_editing ()
5107 step_edit_connection.disconnect ();
5111 Editor::check_step_edit ()
5113 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5114 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5116 mtv->check_step_edit ();
5120 return true; // do it again, till we stop
5124 Editor::scroll_press (Direction dir)
5126 ++_scroll_callbacks;
5128 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5129 /* delay the first auto-repeat */
5135 scroll_backward (1);
5143 scroll_tracks_up_line ();
5147 scroll_tracks_down_line ();
5151 /* do hacky auto-repeat */
5152 if (!_scroll_connection.connected ()) {
5154 _scroll_connection = Glib::signal_timeout().connect (
5155 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5158 _scroll_callbacks = 0;
5165 Editor::scroll_release ()
5167 _scroll_connection.disconnect ();
5170 /** Queue a change for the Editor viewport x origin to follow the playhead */
5172 Editor::reset_x_origin_to_follow_playhead ()
5174 framepos_t const frame = playhead_cursor->current_frame;
5176 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5178 if (_session->transport_speed() < 0) {
5180 if (frame > (current_page_frames() / 2)) {
5181 center_screen (frame-(current_page_frames()/2));
5183 center_screen (current_page_frames()/2);
5190 if (frame < leftmost_frame) {
5192 if (_session->transport_rolling()) {
5193 /* rolling; end up with the playhead at the right of the page */
5194 l = frame - current_page_frames ();
5196 /* not rolling: end up with the playhead 1/4 of the way along the page */
5197 l = frame - current_page_frames() / 4;
5201 if (_session->transport_rolling()) {
5202 /* rolling: end up with the playhead on the left of the page */
5205 /* not rolling: end up with the playhead 3/4 of the way along the page */
5206 l = frame - 3 * current_page_frames() / 4;
5214 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5220 Editor::super_rapid_screen_update ()
5222 if (!_session || !_session->engine().running()) {
5226 /* METERING / MIXER STRIPS */
5228 /* update track meters, if required */
5229 if (is_mapped() && meters_running) {
5230 RouteTimeAxisView* rtv;
5231 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5232 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5233 rtv->fast_update ();
5238 /* and any current mixer strip */
5239 if (current_mixer_strip) {
5240 current_mixer_strip->fast_update ();
5243 /* PLAYHEAD AND VIEWPORT */
5245 framepos_t const frame = _session->audible_frame();
5247 /* There are a few reasons why we might not update the playhead / viewport stuff:
5249 * 1. we don't update things when there's a pending locate request, otherwise
5250 * when the editor requests a locate there is a chance that this method
5251 * will move the playhead before the locate request is processed, causing
5253 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5254 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5257 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5259 last_update_frame = frame;
5261 if (!_dragging_playhead) {
5262 playhead_cursor->set_position (frame);
5265 if (!_stationary_playhead) {
5267 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5268 /* We only do this if we aren't already
5269 handling a visual change (ie if
5270 pending_visual_change.being_handled is
5271 false) so that these requests don't stack
5272 up there are too many of them to handle in
5275 reset_x_origin_to_follow_playhead ();
5280 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5284 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5285 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5286 if (target <= 0.0) {
5289 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5290 target = (target * 0.15) + (current * 0.85);
5296 set_horizontal_position (current);
5305 Editor::session_going_away ()
5307 _have_idled = false;
5309 _session_connections.drop_connections ();
5311 super_rapid_screen_update_connection.disconnect ();
5313 selection->clear ();
5314 cut_buffer->clear ();
5316 clicked_regionview = 0;
5317 clicked_axisview = 0;
5318 clicked_routeview = 0;
5319 entered_regionview = 0;
5321 last_update_frame = 0;
5324 playhead_cursor->canvas_item.hide ();
5326 /* rip everything out of the list displays */
5330 _route_groups->clear ();
5332 /* do this first so that deleting a track doesn't reset cms to null
5333 and thus cause a leak.
5336 if (current_mixer_strip) {
5337 if (current_mixer_strip->get_parent() != 0) {
5338 global_hpacker.remove (*current_mixer_strip);
5340 delete current_mixer_strip;
5341 current_mixer_strip = 0;
5344 /* delete all trackviews */
5346 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5349 track_views.clear ();
5351 zoom_range_clock->set_session (0);
5352 nudge_clock->set_session (0);
5354 editor_list_button.set_active(false);
5355 editor_list_button.set_sensitive(false);
5357 /* clear tempo/meter rulers */
5358 remove_metric_marks ();
5360 clear_marker_display ();
5362 stop_step_editing ();
5364 /* get rid of any existing editor mixer strip */
5366 WindowTitle title(Glib::get_application_name());
5367 title += _("Editor");
5369 set_title (title.get_string());
5371 SessionHandlePtr::session_going_away ();
5376 Editor::show_editor_list (bool yn)
5379 _the_notebook.show ();
5381 _the_notebook.hide ();
5386 Editor::change_region_layering_order (bool from_context_menu)
5388 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5390 if (!clicked_routeview) {
5391 if (layering_order_editor) {
5392 layering_order_editor->hide ();
5397 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5403 boost::shared_ptr<Playlist> pl = track->playlist();
5409 if (layering_order_editor == 0) {
5410 layering_order_editor = new RegionLayeringOrderEditor (*this);
5411 layering_order_editor->set_position (WIN_POS_MOUSE);
5414 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5415 layering_order_editor->maybe_present ();
5419 Editor::update_region_layering_order_editor ()
5421 if (layering_order_editor && layering_order_editor->is_visible ()) {
5422 change_region_layering_order (true);
5427 Editor::setup_fade_images ()
5429 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5430 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5431 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5432 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5433 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5435 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5436 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5437 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5438 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5439 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5441 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5442 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5443 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5444 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5445 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5447 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5448 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5449 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5450 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5451 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5455 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5457 Editor::action_menu_item (std::string const & name)
5459 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5462 return *manage (a->create_menu_item ());
5466 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5468 EventBox* b = manage (new EventBox);
5469 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5470 Label* l = manage (new Label (name));
5474 _the_notebook.append_page (widget, *b);
5478 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5480 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5481 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5484 if (ev->type == GDK_2BUTTON_PRESS) {
5486 /* double-click on a notebook tab shrinks or expands the notebook */
5488 if (_notebook_shrunk) {
5489 if (pre_notebook_shrink_pane_width) {
5490 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5492 _notebook_shrunk = false;
5494 pre_notebook_shrink_pane_width = edit_pane.get_position();
5496 /* this expands the LHS of the edit pane to cover the notebook
5497 PAGE but leaves the tabs visible.
5499 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5500 _notebook_shrunk = true;
5508 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5510 using namespace Menu_Helpers;
5512 MenuList& items = _control_point_context_menu.items ();
5515 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5516 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5517 if (!can_remove_control_point (item)) {
5518 items.back().set_sensitive (false);
5521 _control_point_context_menu.popup (event->button.button, event->button.time);
5525 Editor::shift_key_released ()
5527 _stepping_axis_view = 0;