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 using namespace ARDOUR;
126 using namespace Glib;
127 using namespace Gtkmm2ext;
128 using namespace Editing;
130 using PBD::internationalize;
132 using Gtkmm2ext::Keyboard;
134 const double Editor::timebar_height = 15.0;
136 static const gchar *_snap_type_strings[] = {
138 N_("Timecode Frames"),
139 N_("Timecode Seconds"),
140 N_("Timecode Minutes"),
170 static const gchar *_snap_mode_strings[] = {
177 static const gchar *_edit_point_strings[] = {
184 static const gchar *_zoom_focus_strings[] = {
194 #ifdef USE_RUBBERBAND
195 static const gchar *_rb_opt_strings[] = {
198 N_("Balanced multitimbral mixture"),
199 N_("Unpitched percussion with stable notes"),
200 N_("Crisp monophonic instrumental"),
201 N_("Unpitched solo percussion"),
202 N_("Resample without preserving pitch"),
208 pane_size_watcher (Paned* pane)
210 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
214 Quartz: impossible to access
216 so stop that by preventing it from ever getting too narrow. 35
217 pixels is basically a rough guess at the tab width.
222 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
224 gint pos = pane->get_position ();
226 if (pos > max_width_of_lhs) {
227 pane->set_position (max_width_of_lhs);
232 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
234 /* time display buttons */
235 , minsec_label (_("Mins:Secs"))
236 , bbt_label (_("Bars:Beats"))
237 , timecode_label (_("Timecode"))
238 , samples_label (_("Samples"))
239 , tempo_label (_("Tempo"))
240 , meter_label (_("Meter"))
241 , mark_label (_("Location Markers"))
242 , range_mark_label (_("Range Markers"))
243 , transport_mark_label (_("Loop/Punch Ranges"))
244 , cd_mark_label (_("CD Markers"))
245 , videotl_label (_("Video Timeline"))
246 , edit_packer (4, 4, true)
248 /* the values here don't matter: layout widgets
249 reset them as needed.
252 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
254 /* tool bar related */
256 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
258 , toolbar_selection_clock_table (2,3)
260 , automation_mode_button (_("mode"))
262 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
266 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
267 , meters_running(false)
268 , _pending_locate_request (false)
269 , _pending_initial_locate (false)
270 , _last_cut_copy_source_track (0)
272 , _region_selection_change_updates_region_list (true)
273 , _following_mixer_selection (false)
274 , _control_point_toggled_on_press (false)
275 , _stepping_axis_view (0)
279 /* we are a singleton */
281 PublicEditor::_instance = this;
285 selection = new Selection (this);
286 cut_buffer = new Selection (this);
288 clicked_regionview = 0;
289 clicked_axisview = 0;
290 clicked_routeview = 0;
291 clicked_control_point = 0;
292 last_update_frame = 0;
293 pre_press_cursor = 0;
294 _drags = new DragManager (this);
295 current_mixer_strip = 0;
298 snap_type_strings = I18N (_snap_type_strings);
299 snap_mode_strings = I18N (_snap_mode_strings);
300 zoom_focus_strings = I18N (_zoom_focus_strings);
301 edit_point_strings = I18N (_edit_point_strings);
302 #ifdef USE_RUBBERBAND
303 rb_opt_strings = I18N (_rb_opt_strings);
307 snap_threshold = 5.0;
308 bbt_beat_subdivision = 4;
311 last_autoscroll_x = 0;
312 last_autoscroll_y = 0;
313 autoscroll_active = false;
314 autoscroll_timeout_tag = -1;
319 current_interthread_info = 0;
320 _show_measures = true;
322 show_gain_after_trim = false;
324 have_pending_keyboard_selection = false;
325 _follow_playhead = true;
326 _stationary_playhead = false;
327 editor_ruler_menu = 0;
328 no_ruler_shown_update = false;
330 range_marker_menu = 0;
331 marker_menu_item = 0;
332 tempo_or_meter_marker_menu = 0;
333 transport_marker_menu = 0;
334 new_transport_marker_menu = 0;
335 editor_mixer_strip_width = Wide;
336 show_editor_mixer_when_tracks_arrive = false;
337 region_edit_menu_split_multichannel_item = 0;
338 region_edit_menu_split_item = 0;
341 current_stepping_trackview = 0;
343 entered_regionview = 0;
345 clear_entered_track = false;
348 button_release_can_deselect = true;
349 _dragging_playhead = false;
350 _dragging_edit_point = false;
351 select_new_marker = false;
353 layering_order_editor = 0;
354 no_save_visual = false;
356 within_track_canvas = false;
358 scrubbing_direction = 0;
362 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
363 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
364 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
365 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
366 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
368 zoom_focus = ZoomFocusLeft;
369 _edit_point = EditAtMouse;
370 _internal_editing = false;
371 current_canvas_cursor = 0;
373 frames_per_unit = 2048; /* too early to use reset_zoom () */
375 _scroll_callbacks = 0;
377 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
379 bbt_label.set_name ("EditorRulerLabel");
380 bbt_label.set_size_request (-1, (int)timebar_height);
381 bbt_label.set_alignment (1.0, 0.5);
382 bbt_label.set_padding (5,0);
384 bbt_label.set_no_show_all();
385 minsec_label.set_name ("EditorRulerLabel");
386 minsec_label.set_size_request (-1, (int)timebar_height);
387 minsec_label.set_alignment (1.0, 0.5);
388 minsec_label.set_padding (5,0);
389 minsec_label.hide ();
390 minsec_label.set_no_show_all();
391 timecode_label.set_name ("EditorRulerLabel");
392 timecode_label.set_size_request (-1, (int)timebar_height);
393 timecode_label.set_alignment (1.0, 0.5);
394 timecode_label.set_padding (5,0);
395 timecode_label.hide ();
396 timecode_label.set_no_show_all();
397 samples_label.set_name ("EditorRulerLabel");
398 samples_label.set_size_request (-1, (int)timebar_height);
399 samples_label.set_alignment (1.0, 0.5);
400 samples_label.set_padding (5,0);
401 samples_label.hide ();
402 samples_label.set_no_show_all();
404 tempo_label.set_name ("EditorRulerLabel");
405 tempo_label.set_size_request (-1, (int)timebar_height);
406 tempo_label.set_alignment (1.0, 0.5);
407 tempo_label.set_padding (5,0);
409 tempo_label.set_no_show_all();
411 meter_label.set_name ("EditorRulerLabel");
412 meter_label.set_size_request (-1, (int)timebar_height);
413 meter_label.set_alignment (1.0, 0.5);
414 meter_label.set_padding (5,0);
416 meter_label.set_no_show_all();
418 mark_label.set_name ("EditorRulerLabel");
419 mark_label.set_size_request (-1, (int)timebar_height);
420 mark_label.set_alignment (1.0, 0.5);
421 mark_label.set_padding (5,0);
423 mark_label.set_no_show_all();
425 cd_mark_label.set_name ("EditorRulerLabel");
426 cd_mark_label.set_size_request (-1, (int)timebar_height);
427 cd_mark_label.set_alignment (1.0, 0.5);
428 cd_mark_label.set_padding (5,0);
429 cd_mark_label.hide();
430 cd_mark_label.set_no_show_all();
432 videotl_bar_height = 4;
433 videotl_label.set_name ("EditorRulerLabel");
434 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
435 videotl_label.set_alignment (1.0, 0.5);
436 videotl_label.set_padding (5,0);
437 videotl_label.hide();
438 videotl_label.set_no_show_all();
440 range_mark_label.set_name ("EditorRulerLabel");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 range_mark_label.hide();
445 range_mark_label.set_no_show_all();
447 transport_mark_label.set_name ("EditorRulerLabel");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
451 transport_mark_label.hide();
452 transport_mark_label.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
457 _summary = new EditorSummary (this);
459 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
460 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
462 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
464 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
465 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
467 edit_controls_vbox.set_spacing (0);
468 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
469 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
471 HBox* h = manage (new HBox);
472 _group_tabs = new EditorGroupTabs (this);
473 h->pack_start (*_group_tabs, PACK_SHRINK);
474 h->pack_start (edit_controls_vbox);
475 controls_layout.add (*h);
477 controls_layout.set_name ("EditControlsBase");
478 controls_layout.add_events (Gdk::SCROLL_MASK);
479 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
481 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
482 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
484 _cursors = new MouseCursors;
486 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
487 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
488 0.0, 1.0, 100.0, 1.0));
490 pad_line_1->property_color_rgba() = 0xFF0000FF;
495 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
496 time_canvas_vbox.set_size_request (-1, -1);
498 ruler_label_event_box.add (ruler_label_vbox);
499 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
500 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
502 time_button_event_box.add (time_button_vbox);
503 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
504 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
506 /* these enable us to have a dedicated window (for cursor setting, etc.)
507 for the canvas areas.
510 track_canvas_event_box.add (*track_canvas);
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" */
524 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
530 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
532 bottom_hbox.set_border_width (2);
533 bottom_hbox.set_spacing (3);
535 _route_groups = new EditorRouteGroups (this);
536 _routes = new EditorRoutes (this);
537 _regions = new EditorRegions (this);
538 _snapshots = new EditorSnapshots (this);
539 _locations = new EditorLocations (this);
541 add_notebook_page (_("Regions"), _regions->widget ());
542 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
543 add_notebook_page (_("Snapshots"), _snapshots->widget ());
544 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
545 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
547 _the_notebook.set_show_tabs (true);
548 _the_notebook.set_scrollable (true);
549 _the_notebook.popup_disable ();
550 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
551 _the_notebook.show_all ();
553 _notebook_shrunk = false;
555 editor_summary_pane.pack1(edit_packer);
557 Button* summary_arrows_left_left = manage (new Button);
558 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
559 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
560 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
562 Button* summary_arrows_left_right = manage (new Button);
563 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
564 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
565 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 VBox* summary_arrows_left = manage (new VBox);
568 summary_arrows_left->pack_start (*summary_arrows_left_left);
569 summary_arrows_left->pack_start (*summary_arrows_left_right);
571 Button* summary_arrows_right_up = manage (new Button);
572 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
573 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
574 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 Button* summary_arrows_right_down = manage (new Button);
577 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
578 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
579 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 VBox* summary_arrows_right = manage (new VBox);
582 summary_arrows_right->pack_start (*summary_arrows_right_up);
583 summary_arrows_right->pack_start (*summary_arrows_right_down);
585 Frame* summary_frame = manage (new Frame);
586 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
588 summary_frame->add (*_summary);
589 summary_frame->show ();
591 _summary_hbox.pack_start (*summary_arrows_left, false, false);
592 _summary_hbox.pack_start (*summary_frame, true, true);
593 _summary_hbox.pack_start (*summary_arrows_right, false, false);
595 editor_summary_pane.pack2 (_summary_hbox);
597 edit_pane.pack1 (editor_summary_pane, true, true);
598 edit_pane.pack2 (_the_notebook, false, true);
600 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
602 /* XXX: editor_summary_pane might need similar to the edit_pane */
604 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
606 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
607 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
609 top_hbox.pack_start (toolbar_frame);
611 HBox *hbox = manage (new HBox);
612 hbox->pack_start (edit_pane, true, true);
614 global_vpacker.pack_start (top_hbox, false, false);
615 global_vpacker.pack_start (*hbox, true, true);
617 global_hpacker.pack_start (global_vpacker, true, true);
619 set_name ("EditorWindow");
620 add_accel_group (ActionManager::ui_manager->get_accel_group());
622 status_bar_hpacker.show ();
624 vpacker.pack_end (status_bar_hpacker, false, false);
625 vpacker.pack_end (global_hpacker, true, true);
627 /* register actions now so that set_state() can find them and set toggles/checks etc */
630 /* when we start using our own keybinding system for the editor, this
631 * will be uncommented
637 set_zoom_focus (zoom_focus);
638 _snap_type = SnapToBeat;
639 set_snap_to (_snap_type);
640 _snap_mode = SnapOff;
641 set_snap_mode (_snap_mode);
642 set_mouse_mode (MouseObject, true);
643 pre_internal_mouse_mode = MouseObject;
644 pre_internal_snap_type = _snap_type;
645 pre_internal_snap_mode = _snap_mode;
646 internal_snap_type = _snap_type;
647 internal_snap_mode = _snap_mode;
648 set_edit_point_preference (EditAtMouse, true);
650 _playlist_selector = new PlaylistSelector();
651 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
653 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
657 nudge_forward_button.set_name ("zoom button");
658 nudge_forward_button.add_elements (ArdourButton::FlatFace);
659 nudge_forward_button.set_image(::get_icon("nudge_right"));
661 nudge_backward_button.set_name ("zoom button");
662 nudge_backward_button.add_elements (ArdourButton::FlatFace);
663 nudge_backward_button.set_image(::get_icon("nudge_left"));
665 fade_context_menu.set_name ("ArdourContextMenu");
667 /* icons, titles, WM stuff */
669 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
670 Glib::RefPtr<Gdk::Pixbuf> icon;
672 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
673 window_icons.push_back (icon);
675 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
676 window_icons.push_back (icon);
678 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
679 window_icons.push_back (icon);
681 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
682 window_icons.push_back (icon);
684 if (!window_icons.empty()) {
685 // set_icon_list (window_icons);
686 set_default_icon_list (window_icons);
689 WindowTitle title(Glib::get_application_name());
690 title += _("Editor");
691 set_title (title.get_string());
692 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
695 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
697 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
698 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
700 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
702 /* allow external control surfaces/protocols to do various things */
704 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
705 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
706 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
707 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
708 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
709 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
710 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
711 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
712 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
713 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
714 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
715 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
716 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
717 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
719 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
720 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
721 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
722 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
725 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
727 /* problematic: has to return a value and thus cannot be x-thread */
729 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
731 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
733 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
735 _ignore_region_action = false;
736 _last_region_menu_was_main = false;
737 _popup_region_menu_item = 0;
739 _show_marker_lines = false;
740 _over_region_trim_target = false;
742 /* Button bindings */
744 button_bindings = new Bindings;
746 XMLNode* node = button_settings();
748 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
749 button_bindings->load (**i);
756 setup_fade_images ();
761 delete button_bindings;
763 delete _route_groups;
769 Editor::button_settings () const
771 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
772 XMLNode* node = find_named_node (*settings, X_("Buttons"));
775 node = new XMLNode (X_("Buttons"));
782 Editor::add_toplevel_controls (Container& cont)
784 vpacker.pack_start (cont, false, false);
789 Editor::get_smart_mode () const
791 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
795 Editor::catch_vanishing_regionview (RegionView *rv)
797 /* note: the selection will take care of the vanishing
798 audioregionview by itself.
801 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
805 if (clicked_regionview == rv) {
806 clicked_regionview = 0;
809 if (entered_regionview == rv) {
810 set_entered_regionview (0);
813 if (!_all_region_actions_sensitized) {
814 sensitize_all_region_actions (true);
817 _over_region_trim_target = false;
821 Editor::set_entered_regionview (RegionView* rv)
823 if (rv == entered_regionview) {
827 if (entered_regionview) {
828 entered_regionview->exited ();
831 if ((entered_regionview = rv) != 0) {
832 entered_regionview->entered (internal_editing ());
835 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
836 /* This RegionView entry might have changed what region actions
837 are allowed, so sensitize them all in case a key is pressed.
839 sensitize_all_region_actions (true);
844 Editor::set_entered_track (TimeAxisView* tav)
847 entered_track->exited ();
850 if ((entered_track = tav) != 0) {
851 entered_track->entered ();
856 Editor::show_window ()
858 if (!is_visible ()) {
861 /* XXX: this is a bit unfortunate; it would probably
862 be nicer if we could just call show () above rather
863 than needing the show_all ()
866 /* re-hide stuff if necessary */
867 editor_list_button_toggled ();
868 parameter_changed ("show-summary");
869 parameter_changed ("show-group-tabs");
870 parameter_changed ("show-zoom-tools");
872 /* now reset all audio_time_axis heights, because widgets might need
878 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
879 tv = (static_cast<TimeAxisView*>(*i));
883 if (current_mixer_strip) {
884 current_mixer_strip->hide_things ();
885 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
893 Editor::instant_save ()
895 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
900 _session->add_instant_xml(get_state());
902 Config->add_instant_xml(get_state());
907 Editor::zoom_adjustment_changed ()
913 double fpu = zoom_range_clock->current_duration() / _canvas_width;
914 bool clamped = clamp_frames_per_unit (fpu);
917 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
924 Editor::control_vertical_zoom_in_all ()
926 tav_zoom_smooth (false, true);
930 Editor::control_vertical_zoom_out_all ()
932 tav_zoom_smooth (true, true);
936 Editor::control_vertical_zoom_in_selected ()
938 tav_zoom_smooth (false, false);
942 Editor::control_vertical_zoom_out_selected ()
944 tav_zoom_smooth (true, false);
948 Editor::control_view (uint32_t view)
950 goto_visual_state (view);
954 Editor::control_unselect ()
956 selection->clear_tracks ();
960 Editor::control_select (uint32_t rid, Selection::Operation op)
962 /* handles the (static) signal from the ControlProtocol class that
963 * requests setting the selected track to a given RID
970 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
976 TimeAxisView* tav = axis_view_from_route (r);
981 selection->add (tav);
983 case Selection::Toggle:
984 selection->toggle (tav);
986 case Selection::Extend:
989 selection->set (tav);
993 selection->clear_tracks ();
998 Editor::control_step_tracks_up ()
1000 scroll_tracks_up_line ();
1004 Editor::control_step_tracks_down ()
1006 scroll_tracks_down_line ();
1010 Editor::control_scroll (float fraction)
1012 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1018 double step = fraction * current_page_frames();
1021 _control_scroll_target is an optional<T>
1023 it acts like a pointer to an framepos_t, with
1024 a operator conversion to boolean to check
1025 that it has a value could possibly use
1026 playhead_cursor->current_frame to store the
1027 value and a boolean in the class to know
1028 when it's out of date
1031 if (!_control_scroll_target) {
1032 _control_scroll_target = _session->transport_frame();
1033 _dragging_playhead = true;
1036 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1037 *_control_scroll_target = 0;
1038 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1039 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1041 *_control_scroll_target += (framepos_t) floor (step);
1044 /* move visuals, we'll catch up with it later */
1046 playhead_cursor->set_position (*_control_scroll_target);
1047 UpdateAllTransportClocks (*_control_scroll_target);
1049 if (*_control_scroll_target > (current_page_frames() / 2)) {
1050 /* try to center PH in window */
1051 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1057 Now we do a timeout to actually bring the session to the right place
1058 according to the playhead. This is to avoid reading disk buffers on every
1059 call to control_scroll, which is driven by ScrollTimeline and therefore
1060 probably by a control surface wheel which can generate lots of events.
1062 /* cancel the existing timeout */
1064 control_scroll_connection.disconnect ();
1066 /* add the next timeout */
1068 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1072 Editor::deferred_control_scroll (framepos_t /*target*/)
1074 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1075 // reset for next stream
1076 _control_scroll_target = boost::none;
1077 _dragging_playhead = false;
1082 Editor::access_action (std::string action_group, std::string action_item)
1088 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1091 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1099 Editor::on_realize ()
1101 Window::on_realize ();
1106 Editor::map_position_change (framepos_t frame)
1108 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1110 if (_session == 0) {
1114 if (_follow_playhead) {
1115 center_screen (frame);
1118 playhead_cursor->set_position (frame);
1122 Editor::center_screen (framepos_t frame)
1124 double page = _canvas_width * frames_per_unit;
1126 /* if we're off the page, then scroll.
1129 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1130 center_screen_internal (frame, page);
1135 Editor::center_screen_internal (framepos_t frame, float page)
1140 frame -= (framepos_t) page;
1145 reset_x_origin (frame);
1150 Editor::update_title ()
1152 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1155 bool dirty = _session->dirty();
1157 string session_name;
1159 if (_session->snap_name() != _session->name()) {
1160 session_name = _session->snap_name();
1162 session_name = _session->name();
1166 session_name = "*" + session_name;
1169 WindowTitle title(session_name);
1170 title += Glib::get_application_name();
1171 set_title (title.get_string());
1173 /* ::session_going_away() will have taken care of it */
1178 Editor::set_session (Session *t)
1180 SessionHandlePtr::set_session (t);
1186 zoom_range_clock->set_session (_session);
1187 _playlist_selector->set_session (_session);
1188 nudge_clock->set_session (_session);
1189 _summary->set_session (_session);
1190 _group_tabs->set_session (_session);
1191 _route_groups->set_session (_session);
1192 _regions->set_session (_session);
1193 _snapshots->set_session (_session);
1194 _routes->set_session (_session);
1195 _locations->set_session (_session);
1197 if (rhythm_ferret) {
1198 rhythm_ferret->set_session (_session);
1201 if (analysis_window) {
1202 analysis_window->set_session (_session);
1206 sfbrowser->set_session (_session);
1209 compute_fixed_ruler_scale ();
1211 /* Make sure we have auto loop and auto punch ranges */
1213 Location* loc = _session->locations()->auto_loop_location();
1215 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1217 if (loc->start() == loc->end()) {
1218 loc->set_end (loc->start() + 1);
1221 _session->locations()->add (loc, false);
1222 _session->set_auto_loop_location (loc);
1225 loc->set_name (_("Loop"));
1228 loc = _session->locations()->auto_punch_location();
1231 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1233 if (loc->start() == loc->end()) {
1234 loc->set_end (loc->start() + 1);
1237 _session->locations()->add (loc, false);
1238 _session->set_auto_punch_location (loc);
1241 loc->set_name (_("Punch"));
1244 refresh_location_display ();
1246 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1247 the selected Marker; this needs the LocationMarker list to be available.
1249 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1250 set_state (*node, Stateful::loading_state_version);
1252 /* catch up with the playhead */
1254 _session->request_locate (playhead_cursor->current_frame);
1255 _pending_initial_locate = true;
1259 /* These signals can all be emitted by a non-GUI thread. Therefore the
1260 handlers for them must not attempt to directly interact with the GUI,
1261 but use PBD::Signal<T>::connect() which accepts an event loop
1262 ("context") where the handler will be asked to run.
1265 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1266 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1267 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1268 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1269 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1270 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1271 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1272 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1273 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1274 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1275 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1276 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1277 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1278 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1280 playhead_cursor->canvas_item.show ();
1282 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1283 Config->map_parameters (pc);
1284 _session->config.map_parameters (pc);
1286 restore_ruler_visibility ();
1287 //tempo_map_changed (PropertyChange (0));
1288 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1290 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1291 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1294 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1295 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1298 switch (_snap_type) {
1299 case SnapToRegionStart:
1300 case SnapToRegionEnd:
1301 case SnapToRegionSync:
1302 case SnapToRegionBoundary:
1303 build_region_boundary_cache ();
1310 /* register for undo history */
1311 _session->register_with_memento_command_factory(id(), this);
1313 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1315 start_updating_meters ();
1319 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1321 if (a->get_name() == "RegionMenu") {
1322 /* When the main menu's region menu is opened, we setup the actions so that they look right
1323 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1324 so we resensitize all region actions when the entered regionview or the region selection
1325 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1326 happens after the region context menu is opened. So we set a flag here, too.
1330 sensitize_the_right_region_actions ();
1331 _last_region_menu_was_main = true;
1336 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1338 using namespace Menu_Helpers;
1340 void (Editor::*emf)(FadeShape);
1341 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1344 images = &_xfade_in_images;
1345 emf = &Editor::set_fade_in_shape;
1347 images = &_xfade_out_images;
1348 emf = &Editor::set_fade_out_shape;
1353 _("Linear (for highly correlated material)"),
1354 *(*images)[FadeLinear],
1355 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1359 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1363 _("Constant power"),
1364 *(*images)[FadeConstantPower],
1365 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1368 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 *(*images)[FadeSymmetric],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 *(*images)[FadeSlow],
1384 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeFast],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1396 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 /** Pop up a context menu for when the user clicks on a start crossfade */
1401 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1403 using namespace Menu_Helpers;
1405 MenuList& items (xfade_in_context_menu.items());
1407 if (items.empty()) {
1408 fill_xfade_menu (items, true);
1411 xfade_in_context_menu.popup (button, time);
1414 /** Pop up a context menu for when the user clicks on an end crossfade */
1416 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1418 using namespace Menu_Helpers;
1420 MenuList& items (xfade_out_context_menu.items());
1422 if (items.empty()) {
1423 fill_xfade_menu (items, false);
1426 xfade_out_context_menu.popup (button, time);
1430 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1432 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1434 using namespace Menu_Helpers;
1435 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1438 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1442 MenuList& items (fade_context_menu.items());
1445 switch (item_type) {
1447 case FadeInHandleItem:
1448 if (arv->audio_region()->fade_in_active()) {
1449 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1451 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1454 items.push_back (SeparatorElem());
1456 if (Profile->get_sae()) {
1458 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1459 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1466 *_fade_in_images[FadeLinear],
1467 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 *_fade_in_images[FadeSlow],
1477 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *_fade_in_images[FadeFast],
1486 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *_fade_in_images[FadeSymmetric],
1495 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1500 _("Constant power"),
1501 *_fade_in_images[FadeConstantPower],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 case FadeOutHandleItem:
1512 if (arv->audio_region()->fade_out_active()) {
1513 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1515 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1518 items.push_back (SeparatorElem());
1520 if (Profile->get_sae()) {
1521 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1522 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1528 *_fade_out_images[FadeLinear],
1529 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1533 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1538 *_fade_out_images[FadeSlow],
1539 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1542 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1547 *_fade_out_images[FadeFast],
1548 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1551 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1556 *_fade_out_images[FadeSymmetric],
1557 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1562 _("Constant power"),
1563 *_fade_out_images[FadeConstantPower],
1564 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1567 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1573 fatal << _("programming error: ")
1574 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1579 fade_context_menu.popup (button, time);
1583 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1585 using namespace Menu_Helpers;
1586 Menu* (Editor::*build_menu_function)();
1589 switch (item_type) {
1591 case RegionViewName:
1592 case RegionViewNameHighlight:
1593 case LeftFrameHandle:
1594 case RightFrameHandle:
1595 if (with_selection) {
1596 build_menu_function = &Editor::build_track_selection_context_menu;
1598 build_menu_function = &Editor::build_track_region_context_menu;
1603 if (with_selection) {
1604 build_menu_function = &Editor::build_track_selection_context_menu;
1606 build_menu_function = &Editor::build_track_context_menu;
1611 if (clicked_routeview->track()) {
1612 build_menu_function = &Editor::build_track_context_menu;
1614 build_menu_function = &Editor::build_track_bus_context_menu;
1619 /* probably shouldn't happen but if it does, we don't care */
1623 menu = (this->*build_menu_function)();
1624 menu->set_name ("ArdourContextMenu");
1626 /* now handle specific situations */
1628 switch (item_type) {
1630 case RegionViewName:
1631 case RegionViewNameHighlight:
1632 case LeftFrameHandle:
1633 case RightFrameHandle:
1634 if (!with_selection) {
1635 if (region_edit_menu_split_item) {
1636 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1637 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1639 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1642 if (region_edit_menu_split_multichannel_item) {
1643 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1644 region_edit_menu_split_multichannel_item->set_sensitive (true);
1646 region_edit_menu_split_multichannel_item->set_sensitive (false);
1659 /* probably shouldn't happen but if it does, we don't care */
1663 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1665 /* Bounce to disk */
1667 using namespace Menu_Helpers;
1668 MenuList& edit_items = menu->items();
1670 edit_items.push_back (SeparatorElem());
1672 switch (clicked_routeview->audio_track()->freeze_state()) {
1673 case AudioTrack::NoFreeze:
1674 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1677 case AudioTrack::Frozen:
1678 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1681 case AudioTrack::UnFrozen:
1682 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1688 if (item_type == StreamItem && clicked_routeview) {
1689 clicked_routeview->build_underlay_menu(menu);
1692 /* When the region menu is opened, we setup the actions so that they look right
1695 sensitize_the_right_region_actions ();
1696 _last_region_menu_was_main = false;
1698 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1699 menu->popup (button, time);
1703 Editor::build_track_context_menu ()
1705 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_context_menu.items();
1710 add_dstream_context_items (edit_items);
1711 return &track_context_menu;
1715 Editor::build_track_bus_context_menu ()
1717 using namespace Menu_Helpers;
1719 MenuList& edit_items = track_context_menu.items();
1722 add_bus_context_items (edit_items);
1723 return &track_context_menu;
1727 Editor::build_track_region_context_menu ()
1729 using namespace Menu_Helpers;
1730 MenuList& edit_items = track_region_context_menu.items();
1733 /* we've just cleared the track region context menu, so the menu that these
1734 two items were on will have disappeared; stop them dangling.
1736 region_edit_menu_split_item = 0;
1737 region_edit_menu_split_multichannel_item = 0;
1739 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1742 boost::shared_ptr<Track> tr;
1743 boost::shared_ptr<Playlist> pl;
1745 if ((tr = rtv->track())) {
1746 add_region_context_items (edit_items, tr);
1750 add_dstream_context_items (edit_items);
1752 return &track_region_context_menu;
1756 Editor::analyze_region_selection ()
1758 if (analysis_window == 0) {
1759 analysis_window = new AnalysisWindow();
1762 analysis_window->set_session(_session);
1764 analysis_window->show_all();
1767 analysis_window->set_regionmode();
1768 analysis_window->analyze();
1770 analysis_window->present();
1774 Editor::analyze_range_selection()
1776 if (analysis_window == 0) {
1777 analysis_window = new AnalysisWindow();
1780 analysis_window->set_session(_session);
1782 analysis_window->show_all();
1785 analysis_window->set_rangemode();
1786 analysis_window->analyze();
1788 analysis_window->present();
1792 Editor::build_track_selection_context_menu ()
1794 using namespace Menu_Helpers;
1795 MenuList& edit_items = track_selection_context_menu.items();
1796 edit_items.clear ();
1798 add_selection_context_items (edit_items);
1799 // edit_items.push_back (SeparatorElem());
1800 // add_dstream_context_items (edit_items);
1802 return &track_selection_context_menu;
1806 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1808 using namespace Menu_Helpers;
1810 /* OK, stick the region submenu at the top of the list, and then add
1814 RegionSelection rs = get_regions_from_selection_and_entered ();
1816 string::size_type pos = 0;
1817 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1819 /* we have to hack up the region name because "_" has a special
1820 meaning for menu titles.
1823 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1824 menu_item_name.replace (pos, 1, "__");
1828 if (_popup_region_menu_item == 0) {
1829 _popup_region_menu_item = new MenuItem (menu_item_name);
1830 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1831 _popup_region_menu_item->show ();
1833 _popup_region_menu_item->set_label (menu_item_name);
1836 const framepos_t position = get_preferred_edit_position (false, true);
1838 edit_items.push_back (*_popup_region_menu_item);
1839 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1840 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1842 edit_items.push_back (SeparatorElem());
1845 /** Add context menu items relevant to selection ranges.
1846 * @param edit_items List to add the items to.
1849 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1851 using namespace Menu_Helpers;
1853 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1854 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1856 edit_items.push_back (SeparatorElem());
1857 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1859 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (
1863 _("Move Range Start to Previous Region Boundary"),
1864 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1868 edit_items.push_back (
1870 _("Move Range Start to Next Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1875 edit_items.push_back (
1877 _("Move Range End to Previous Region Boundary"),
1878 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1882 edit_items.push_back (
1884 _("Move Range End to Next Region Boundary"),
1885 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1889 edit_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1891 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1893 edit_items.push_back (SeparatorElem());
1894 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1898 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1905 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1906 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1910 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1911 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1912 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1913 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1914 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1915 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1921 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1923 using namespace Menu_Helpers;
1927 Menu *play_menu = manage (new Menu);
1928 MenuList& play_items = play_menu->items();
1929 play_menu->set_name ("ArdourContextMenu");
1931 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1932 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1933 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1934 play_items.push_back (SeparatorElem());
1935 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1937 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1941 Menu *select_menu = manage (new Menu);
1942 MenuList& select_items = select_menu->items();
1943 select_menu->set_name ("ArdourContextMenu");
1945 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1946 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1947 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1948 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1949 select_items.push_back (SeparatorElem());
1950 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1951 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1954 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1955 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1956 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1957 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1958 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1959 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1961 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1965 Menu *cutnpaste_menu = manage (new Menu);
1966 MenuList& cutnpaste_items = cutnpaste_menu->items();
1967 cutnpaste_menu->set_name ("ArdourContextMenu");
1969 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1970 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1971 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1973 cutnpaste_items.push_back (SeparatorElem());
1975 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1976 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1978 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1980 /* Adding new material */
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1984 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1988 Menu *nudge_menu = manage (new Menu());
1989 MenuList& nudge_items = nudge_menu->items();
1990 nudge_menu->set_name ("ArdourContextMenu");
1992 edit_items.push_back (SeparatorElem());
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1995 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1996 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1998 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2002 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2004 using namespace Menu_Helpers;
2008 Menu *play_menu = manage (new Menu);
2009 MenuList& play_items = play_menu->items();
2010 play_menu->set_name ("ArdourContextMenu");
2012 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2013 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2014 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2018 Menu *select_menu = manage (new Menu);
2019 MenuList& select_items = select_menu->items();
2020 select_menu->set_name ("ArdourContextMenu");
2022 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2025 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2028 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2029 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2030 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2032 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2036 Menu *cutnpaste_menu = manage (new Menu);
2037 MenuList& cutnpaste_items = cutnpaste_menu->items();
2038 cutnpaste_menu->set_name ("ArdourContextMenu");
2040 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2041 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2042 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2044 Menu *nudge_menu = manage (new Menu());
2045 MenuList& nudge_items = nudge_menu->items();
2046 nudge_menu->set_name ("ArdourContextMenu");
2048 edit_items.push_back (SeparatorElem());
2049 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2050 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2051 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2052 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2054 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2058 Editor::snap_type() const
2064 Editor::snap_mode() const
2070 Editor::set_snap_to (SnapType st)
2072 unsigned int snap_ind = (unsigned int)st;
2076 if (snap_ind > snap_type_strings.size() - 1) {
2078 _snap_type = (SnapType)snap_ind;
2081 string str = snap_type_strings[snap_ind];
2083 if (str != snap_type_selector.get_active_text()) {
2084 snap_type_selector.set_active_text (str);
2089 switch (_snap_type) {
2090 case SnapToBeatDiv128:
2091 case SnapToBeatDiv64:
2092 case SnapToBeatDiv32:
2093 case SnapToBeatDiv28:
2094 case SnapToBeatDiv24:
2095 case SnapToBeatDiv20:
2096 case SnapToBeatDiv16:
2097 case SnapToBeatDiv14:
2098 case SnapToBeatDiv12:
2099 case SnapToBeatDiv10:
2100 case SnapToBeatDiv8:
2101 case SnapToBeatDiv7:
2102 case SnapToBeatDiv6:
2103 case SnapToBeatDiv5:
2104 case SnapToBeatDiv4:
2105 case SnapToBeatDiv3:
2106 case SnapToBeatDiv2: {
2107 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2108 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2110 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2111 current_bbt_points_begin, current_bbt_points_end);
2112 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2113 current_bbt_points_begin, current_bbt_points_end);
2114 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2118 case SnapToRegionStart:
2119 case SnapToRegionEnd:
2120 case SnapToRegionSync:
2121 case SnapToRegionBoundary:
2122 build_region_boundary_cache ();
2130 SnapChanged (); /* EMIT SIGNAL */
2134 Editor::set_snap_mode (SnapMode mode)
2136 string str = snap_mode_strings[(int)mode];
2138 if (_internal_editing) {
2139 internal_snap_mode = mode;
2141 pre_internal_snap_mode = mode;
2146 if (str != snap_mode_selector.get_active_text ()) {
2147 snap_mode_selector.set_active_text (str);
2153 Editor::set_edit_point_preference (EditPoint ep, bool force)
2155 bool changed = (_edit_point != ep);
2158 string str = edit_point_strings[(int)ep];
2160 if (str != edit_point_selector.get_active_text ()) {
2161 edit_point_selector.set_active_text (str);
2164 set_canvas_cursor ();
2166 if (!force && !changed) {
2170 const char* action=NULL;
2172 switch (_edit_point) {
2173 case EditAtPlayhead:
2174 action = "edit-at-playhead";
2176 case EditAtSelectedMarker:
2177 action = "edit-at-marker";
2180 action = "edit-at-mouse";
2184 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2186 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2190 bool in_track_canvas;
2192 if (!mouse_frame (foo, in_track_canvas)) {
2193 in_track_canvas = false;
2196 reset_canvas_action_sensitivity (in_track_canvas);
2202 Editor::set_state (const XMLNode& node, int /*version*/)
2204 const XMLProperty* prop;
2211 g.base_width = default_width;
2212 g.base_height = default_height;
2216 if ((geometry = find_named_node (node, "geometry")) != 0) {
2220 if ((prop = geometry->property("x_size")) == 0) {
2221 prop = geometry->property ("x-size");
2224 g.base_width = atoi(prop->value());
2226 if ((prop = geometry->property("y_size")) == 0) {
2227 prop = geometry->property ("y-size");
2230 g.base_height = atoi(prop->value());
2233 if ((prop = geometry->property ("x_pos")) == 0) {
2234 prop = geometry->property ("x-pos");
2237 x = atoi (prop->value());
2240 if ((prop = geometry->property ("y_pos")) == 0) {
2241 prop = geometry->property ("y-pos");
2244 y = atoi (prop->value());
2248 set_default_size (g.base_width, g.base_height);
2251 if (_session && (prop = node.property ("playhead"))) {
2253 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2254 playhead_cursor->set_position (pos);
2256 playhead_cursor->set_position (0);
2259 if ((prop = node.property ("mixer-width"))) {
2260 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2263 if ((prop = node.property ("zoom-focus"))) {
2264 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2267 if ((prop = node.property ("zoom"))) {
2268 reset_zoom (PBD::atof (prop->value()));
2270 reset_zoom (frames_per_unit);
2273 if ((prop = node.property ("snap-to"))) {
2274 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2277 if ((prop = node.property ("snap-mode"))) {
2278 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2281 if ((prop = node.property ("internal-snap-to"))) {
2282 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2285 if ((prop = node.property ("internal-snap-mode"))) {
2286 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2289 if ((prop = node.property ("pre-internal-snap-to"))) {
2290 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2294 if ((prop = node.property ("pre-internal-snap-mode"))) {
2295 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2298 if ((prop = node.property ("mouse-mode"))) {
2299 MouseMode m = str2mousemode(prop->value());
2300 set_mouse_mode (m, true);
2302 set_mouse_mode (MouseObject, true);
2305 if ((prop = node.property ("left-frame")) != 0) {
2307 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2311 reset_x_origin (pos);
2315 if ((prop = node.property ("y-origin")) != 0) {
2316 reset_y_origin (atof (prop->value ()));
2319 if ((prop = node.property ("internal-edit"))) {
2320 bool yn = string_is_affirmative (prop->value());
2321 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2323 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2329 if ((prop = node.property ("join-object-range"))) {
2330 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2331 bool yn = string_is_affirmative (prop->value());
2333 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334 tact->set_active (!yn);
2335 tact->set_active (yn);
2337 set_mouse_mode(mouse_mode, true);
2340 if ((prop = node.property ("edit-point"))) {
2341 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2344 if ((prop = node.property ("show-measures"))) {
2345 bool yn = string_is_affirmative (prop->value());
2346 _show_measures = yn;
2347 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2349 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2350 /* do it twice to force the change */
2351 tact->set_active (!yn);
2352 tact->set_active (yn);
2356 if ((prop = node.property ("follow-playhead"))) {
2357 bool yn = string_is_affirmative (prop->value());
2358 set_follow_playhead (yn);
2359 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2361 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2362 if (tact->get_active() != yn) {
2363 tact->set_active (yn);
2368 if ((prop = node.property ("stationary-playhead"))) {
2369 bool yn = string_is_affirmative (prop->value());
2370 set_stationary_playhead (yn);
2371 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2373 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2374 if (tact->get_active() != yn) {
2375 tact->set_active (yn);
2380 if ((prop = node.property ("region-list-sort-type"))) {
2381 RegionListSortType st;
2382 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2385 if ((prop = node.property ("show-editor-mixer"))) {
2387 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2390 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2391 bool yn = string_is_affirmative (prop->value());
2393 /* do it twice to force the change */
2395 tact->set_active (!yn);
2396 tact->set_active (yn);
2399 if ((prop = node.property ("show-editor-list"))) {
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2405 bool yn = string_is_affirmative (prop->value());
2407 /* do it twice to force the change */
2409 tact->set_active (!yn);
2410 tact->set_active (yn);
2413 if ((prop = node.property (X_("editor-list-page")))) {
2414 _the_notebook.set_current_page (atoi (prop->value ()));
2417 if ((prop = node.property (X_("show-marker-lines")))) {
2418 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2420 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2421 bool yn = string_is_affirmative (prop->value ());
2423 tact->set_active (!yn);
2424 tact->set_active (yn);
2427 XMLNodeList children = node.children ();
2428 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2429 selection->set_state (**i, Stateful::current_state_version);
2430 _regions->set_state (**i);
2433 if ((prop = node.property ("maximised"))) {
2434 bool yn = string_is_affirmative (prop->value());
2436 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2440 if ((prop = node.property ("nudge-clock-value"))) {
2442 sscanf (prop->value().c_str(), "%" PRId64, &f);
2443 nudge_clock->set (f);
2445 nudge_clock->set_mode (AudioClock::Timecode);
2446 nudge_clock->set (_session->frame_rate() * 5, true);
2453 Editor::get_state ()
2455 XMLNode* node = new XMLNode ("Editor");
2458 id().print (buf, sizeof (buf));
2459 node->add_property ("id", buf);
2461 if (is_realized()) {
2462 Glib::RefPtr<Gdk::Window> win = get_window();
2464 int x, y, width, height;
2465 win->get_root_origin(x, y);
2466 win->get_size(width, height);
2468 XMLNode* geometry = new XMLNode ("geometry");
2470 snprintf(buf, sizeof(buf), "%d", width);
2471 geometry->add_property("x-size", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", height);
2473 geometry->add_property("y-size", string(buf));
2474 snprintf(buf, sizeof(buf), "%d", x);
2475 geometry->add_property("x-pos", string(buf));
2476 snprintf(buf, sizeof(buf), "%d", y);
2477 geometry->add_property("y-pos", string(buf));
2478 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2479 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2480 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2481 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2482 geometry->add_property("edit-vertical-pane-pos", string(buf));
2484 node->add_child_nocopy (*geometry);
2487 maybe_add_mixer_strip_width (*node);
2489 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2490 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2491 node->add_property ("zoom", buf);
2492 node->add_property ("snap-to", enum_2_string (_snap_type));
2493 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2494 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2495 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2496 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2497 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2498 node->add_property ("edit-point", enum_2_string (_edit_point));
2500 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2501 node->add_property ("playhead", buf);
2502 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2503 node->add_property ("left-frame", buf);
2504 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2505 node->add_property ("y-origin", buf);
2507 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2508 node->add_property ("maximised", _maximised ? "yes" : "no");
2509 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2510 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2511 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2512 node->add_property ("mouse-mode", enum2str(mouse_mode));
2513 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2514 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2516 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2518 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2519 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2522 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2525 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2528 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2529 node->add_property (X_("editor-list-page"), buf);
2531 if (button_bindings) {
2532 XMLNode* bb = new XMLNode (X_("Buttons"));
2533 button_bindings->save (*bb);
2534 node->add_child_nocopy (*bb);
2537 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2539 node->add_child_nocopy (selection->get_state ());
2540 node->add_child_nocopy (_regions->get_state ());
2542 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2543 node->add_property ("nudge-clock-value", buf);
2550 /** @param y y offset from the top of all trackviews.
2551 * @return pair: TimeAxisView that y is over, layer index.
2552 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2553 * in stacked or expanded region display mode, otherwise 0.
2555 std::pair<TimeAxisView *, double>
2556 Editor::trackview_by_y_position (double y)
2558 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2560 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2566 return std::make_pair ( (TimeAxisView *) 0, 0);
2569 /** Snap a position to the grid, if appropriate, taking into account current
2570 * grid settings and also the state of any snap modifier keys that may be pressed.
2571 * @param start Position to snap.
2572 * @param event Event to get current key modifier information from, or 0.
2575 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2577 if (!_session || !event) {
2581 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2582 if (_snap_mode == SnapOff) {
2583 snap_to_internal (start, direction, for_mark);
2586 if (_snap_mode != SnapOff) {
2587 snap_to_internal (start, direction, for_mark);
2593 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2595 if (!_session || _snap_mode == SnapOff) {
2599 snap_to_internal (start, direction, for_mark);
2603 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2605 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2606 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2608 switch (_snap_type) {
2609 case SnapToTimecodeFrame:
2610 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2611 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2613 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2617 case SnapToTimecodeSeconds:
2618 if (_session->config.get_timecode_offset_negative()) {
2619 start += _session->config.get_timecode_offset ();
2621 start -= _session->config.get_timecode_offset ();
2623 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2624 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2626 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2629 if (_session->config.get_timecode_offset_negative()) {
2630 start -= _session->config.get_timecode_offset ();
2632 start += _session->config.get_timecode_offset ();
2636 case SnapToTimecodeMinutes:
2637 if (_session->config.get_timecode_offset_negative()) {
2638 start += _session->config.get_timecode_offset ();
2640 start -= _session->config.get_timecode_offset ();
2642 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2643 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2645 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2647 if (_session->config.get_timecode_offset_negative()) {
2648 start -= _session->config.get_timecode_offset ();
2650 start += _session->config.get_timecode_offset ();
2654 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2660 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2662 const framepos_t one_second = _session->frame_rate();
2663 const framepos_t one_minute = _session->frame_rate() * 60;
2664 framepos_t presnap = start;
2668 switch (_snap_type) {
2669 case SnapToTimecodeFrame:
2670 case SnapToTimecodeSeconds:
2671 case SnapToTimecodeMinutes:
2672 return timecode_snap_to_internal (start, direction, for_mark);
2675 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2676 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2678 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2683 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2684 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2686 start = (framepos_t) floor ((double) start / one_second) * one_second;
2691 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2694 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2699 start = _session->tempo_map().round_to_bar (start, direction);
2703 start = _session->tempo_map().round_to_beat (start, direction);
2706 case SnapToBeatDiv128:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2709 case SnapToBeatDiv64:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2712 case SnapToBeatDiv32:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2715 case SnapToBeatDiv28:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2718 case SnapToBeatDiv24:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2721 case SnapToBeatDiv20:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2724 case SnapToBeatDiv16:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2727 case SnapToBeatDiv14:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2730 case SnapToBeatDiv12:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2733 case SnapToBeatDiv10:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2736 case SnapToBeatDiv8:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2739 case SnapToBeatDiv7:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2742 case SnapToBeatDiv6:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2745 case SnapToBeatDiv5:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2748 case SnapToBeatDiv4:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2751 case SnapToBeatDiv3:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2754 case SnapToBeatDiv2:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2763 _session->locations()->marks_either_side (start, before, after);
2765 if (before == max_framepos && after == max_framepos) {
2766 /* No marks to snap to, so just don't snap */
2768 } else if (before == max_framepos) {
2770 } else if (after == max_framepos) {
2772 } else if (before != max_framepos && after != max_framepos) {
2773 /* have before and after */
2774 if ((start - before) < (after - start)) {
2783 case SnapToRegionStart:
2784 case SnapToRegionEnd:
2785 case SnapToRegionSync:
2786 case SnapToRegionBoundary:
2787 if (!region_boundary_cache.empty()) {
2789 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2790 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2792 if (direction > 0) {
2793 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2795 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2798 if (next != region_boundary_cache.begin ()) {
2803 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2804 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2806 if (start > (p + n) / 2) {
2815 switch (_snap_mode) {
2821 if (presnap > start) {
2822 if (presnap > (start + unit_to_frame(snap_threshold))) {
2826 } else if (presnap < start) {
2827 if (presnap < (start - unit_to_frame(snap_threshold))) {
2833 /* handled at entry */
2841 Editor::setup_toolbar ()
2843 HBox* mode_box = manage(new HBox);
2844 mode_box->set_border_width (2);
2845 mode_box->set_spacing(4);
2847 HBox* mouse_mode_box = manage (new HBox);
2848 HBox* mouse_mode_hbox = manage (new HBox);
2849 VBox* mouse_mode_vbox = manage (new VBox);
2850 Alignment* mouse_mode_align = manage (new Alignment);
2852 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2853 // mouse_mode_size_group->add_widget (smart_mode_button);
2854 mouse_mode_size_group->add_widget (mouse_move_button);
2855 mouse_mode_size_group->add_widget (mouse_select_button);
2856 mouse_mode_size_group->add_widget (mouse_zoom_button);
2857 mouse_mode_size_group->add_widget (mouse_gain_button);
2858 mouse_mode_size_group->add_widget (mouse_timefx_button);
2859 mouse_mode_size_group->add_widget (mouse_audition_button);
2860 mouse_mode_size_group->add_widget (mouse_draw_button);
2861 mouse_mode_size_group->add_widget (internal_edit_button);
2863 /* make them just a bit bigger */
2864 mouse_move_button.set_size_request (-1, 30);
2866 mouse_mode_hbox->set_spacing (2);
2868 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2876 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2878 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2880 mouse_mode_align->add (*mouse_mode_vbox);
2881 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2883 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2885 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2886 if (!Profile->get_sae()) {
2887 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2889 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2891 edit_mode_selector.set_name ("EditModeSelector");
2892 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2893 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2895 mode_box->pack_start (edit_mode_selector, false, false);
2896 mode_box->pack_start (*mouse_mode_box, false, false);
2898 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2899 _mouse_mode_tearoff->set_name ("MouseModeBase");
2900 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2902 if (Profile->get_sae()) {
2903 _mouse_mode_tearoff->set_can_be_torn_off (false);
2906 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window()));
2908 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window(), 1));
2910 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2911 &_mouse_mode_tearoff->tearoff_window()));
2912 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2913 &_mouse_mode_tearoff->tearoff_window(), 1));
2917 _zoom_box.set_spacing (2);
2918 _zoom_box.set_border_width (2);
2922 zoom_in_button.set_name ("zoom button");
2923 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2924 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2925 zoom_in_button.set_image(::get_icon ("zoom_in"));
2926 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2927 zoom_in_button.set_related_action (act);
2929 zoom_out_button.set_name ("zoom button");
2930 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2931 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2932 zoom_out_button.set_image(::get_icon ("zoom_out"));
2933 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2934 zoom_out_button.set_related_action (act);
2936 zoom_out_full_button.set_name ("zoom button");
2937 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2938 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2939 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2940 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2941 zoom_out_full_button.set_related_action (act);
2943 zoom_focus_selector.set_name ("ZoomFocusSelector");
2944 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2945 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2947 _zoom_box.pack_start (zoom_out_button, false, false);
2948 _zoom_box.pack_start (zoom_in_button, false, false);
2949 _zoom_box.pack_start (zoom_out_full_button, false, false);
2951 _zoom_box.pack_start (zoom_focus_selector, false, false);
2953 /* Track zoom buttons */
2954 tav_expand_button.set_name ("zoom button");
2955 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2956 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2957 tav_expand_button.set_size_request (-1, 20);
2958 tav_expand_button.set_image(::get_icon ("tav_exp"));
2959 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2960 tav_expand_button.set_related_action (act);
2962 tav_shrink_button.set_name ("zoom button");
2963 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2964 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2965 tav_shrink_button.set_size_request (-1, 20);
2966 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2967 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2968 tav_shrink_button.set_related_action (act);
2970 _zoom_box.pack_start (tav_shrink_button);
2971 _zoom_box.pack_start (tav_expand_button);
2973 _zoom_tearoff = manage (new TearOff (_zoom_box));
2975 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2976 &_zoom_tearoff->tearoff_window()));
2977 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2978 &_zoom_tearoff->tearoff_window(), 0));
2979 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2980 &_zoom_tearoff->tearoff_window()));
2981 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window(), 0));
2984 snap_box.set_spacing (2);
2985 snap_box.set_border_width (2);
2987 snap_type_selector.set_name ("SnapTypeSelector");
2988 set_popdown_strings (snap_type_selector, snap_type_strings);
2989 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2991 snap_mode_selector.set_name ("SnapModeSelector");
2992 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2993 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2995 edit_point_selector.set_name ("EditPointSelector");
2996 set_popdown_strings (edit_point_selector, edit_point_strings);
2997 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2999 snap_box.pack_start (snap_mode_selector, false, false);
3000 snap_box.pack_start (snap_type_selector, false, false);
3001 snap_box.pack_start (edit_point_selector, false, false);
3005 HBox *nudge_box = manage (new HBox);
3006 nudge_box->set_spacing (2);
3007 nudge_box->set_border_width (2);
3009 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3010 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3012 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3013 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3015 nudge_box->pack_start (nudge_backward_button, false, false);
3016 nudge_box->pack_start (nudge_forward_button, false, false);
3017 nudge_box->pack_start (*nudge_clock, false, false);
3020 /* Pack everything in... */
3022 HBox* hbox = manage (new HBox);
3023 hbox->set_spacing(10);
3025 _tools_tearoff = manage (new TearOff (*hbox));
3026 _tools_tearoff->set_name ("MouseModeBase");
3027 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3029 if (Profile->get_sae()) {
3030 _tools_tearoff->set_can_be_torn_off (false);
3033 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3034 &_tools_tearoff->tearoff_window()));
3035 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window(), 0));
3037 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window()));
3039 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window(), 0));
3042 toolbar_hbox.set_spacing (10);
3043 toolbar_hbox.set_border_width (1);
3045 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3046 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3047 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3049 hbox->pack_start (snap_box, false, false);
3050 if (!Profile->get_small_screen()) {
3051 hbox->pack_start (*nudge_box, false, false);
3053 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3055 hbox->pack_start (panic_box, false, false);
3059 toolbar_base.set_name ("ToolBarBase");
3060 toolbar_base.add (toolbar_hbox);
3062 _toolbar_viewport.add (toolbar_base);
3063 /* stick to the required height but allow width to vary if there's not enough room */
3064 _toolbar_viewport.set_size_request (1, -1);
3066 toolbar_frame.set_shadow_type (SHADOW_OUT);
3067 toolbar_frame.set_name ("BaseFrame");
3068 toolbar_frame.add (_toolbar_viewport);
3072 Editor::setup_tooltips ()
3074 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3075 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3076 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3077 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3078 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3079 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3080 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3081 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3082 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3083 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3084 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3085 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3086 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3087 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3088 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3089 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3090 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3091 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3092 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3093 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3094 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3095 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3096 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3100 Editor::convert_drop_to_paths (
3101 vector<string>& paths,
3102 const RefPtr<Gdk::DragContext>& /*context*/,
3105 const SelectionData& data,
3109 if (_session == 0) {
3113 vector<string> uris = data.get_uris();
3117 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3118 are actually URI lists. So do it by hand.
3121 if (data.get_target() != "text/plain") {
3125 /* Parse the "uri-list" format that Nautilus provides,
3126 where each pathname is delimited by \r\n.
3128 THERE MAY BE NO NULL TERMINATING CHAR!!!
3131 string txt = data.get_text();
3135 p = (char *) malloc (txt.length() + 1);
3136 txt.copy (p, txt.length(), 0);
3137 p[txt.length()] = '\0';
3143 while (g_ascii_isspace (*p))
3147 while (*q && (*q != '\n') && (*q != '\r')) {
3154 while (q > p && g_ascii_isspace (*q))
3159 uris.push_back (string (p, q - p + 1));
3163 p = strchr (p, '\n');
3175 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3177 if ((*i).substr (0,7) == "file://") {
3179 string const p = PBD::url_decode (*i);
3181 // scan forward past three slashes
3183 string::size_type slashcnt = 0;
3184 string::size_type n = 0;
3185 string::const_iterator x = p.begin();
3187 while (slashcnt < 3 && x != p.end()) {
3190 } else if (slashcnt == 3) {
3197 if (slashcnt != 3 || x == p.end()) {
3198 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3202 paths.push_back (p.substr (n - 1));
3210 Editor::new_tempo_section ()
3216 Editor::map_transport_state ()
3218 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3220 if (_session && _session->transport_stopped()) {
3221 have_pending_keyboard_selection = false;
3224 update_loop_range_view (true);
3230 Editor::begin_reversible_command (string name)
3233 _session->begin_reversible_command (name);
3238 Editor::begin_reversible_command (GQuark q)
3241 _session->begin_reversible_command (q);
3246 Editor::commit_reversible_command ()
3249 _session->commit_reversible_command ();
3254 Editor::history_changed ()
3258 if (undo_action && _session) {
3259 if (_session->undo_depth() == 0) {
3260 label = S_("Command|Undo");
3262 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3264 undo_action->property_label() = label;
3267 if (redo_action && _session) {
3268 if (_session->redo_depth() == 0) {
3271 label = string_compose(_("Redo (%1)"), _session->next_redo());
3273 redo_action->property_label() = label;
3278 Editor::duplicate_range (bool with_dialog)
3282 RegionSelection rs = get_regions_from_selection_and_entered ();
3284 if ( selection->time.length() == 0 && rs.empty()) {
3290 ArdourDialog win (_("Duplicate"));
3291 Label label (_("Number of duplications:"));
3292 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3293 SpinButton spinner (adjustment, 0.0, 1);
3296 win.get_vbox()->set_spacing (12);
3297 win.get_vbox()->pack_start (hbox);
3298 hbox.set_border_width (6);
3299 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3301 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3302 place, visually. so do this by hand.
3305 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3306 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3307 spinner.grab_focus();
3313 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3314 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3315 win.set_default_response (RESPONSE_ACCEPT);
3317 spinner.grab_focus ();
3319 switch (win.run ()) {
3320 case RESPONSE_ACCEPT:
3326 times = adjustment.get_value();
3329 if ((current_mouse_mode() == Editing::MouseRange)) {
3330 if (selection->time.length()) {
3331 duplicate_selection (times);
3333 } else if (get_smart_mode()) {
3334 if (selection->time.length()) {
3335 duplicate_selection (times);
3337 duplicate_some_regions (rs, times);
3339 duplicate_some_regions (rs, times);
3344 Editor::set_edit_mode (EditMode m)
3346 Config->set_edit_mode (m);
3350 Editor::cycle_edit_mode ()
3352 switch (Config->get_edit_mode()) {
3354 if (Profile->get_sae()) {
3355 Config->set_edit_mode (Lock);
3357 Config->set_edit_mode (Splice);
3361 Config->set_edit_mode (Lock);
3364 Config->set_edit_mode (Slide);
3370 Editor::edit_mode_selection_done ()
3372 string s = edit_mode_selector.get_active_text ();
3375 Config->set_edit_mode (string_to_edit_mode (s));
3380 Editor::snap_type_selection_done ()
3382 string choice = snap_type_selector.get_active_text();
3383 SnapType snaptype = SnapToBeat;
3385 if (choice == _("Beats/2")) {
3386 snaptype = SnapToBeatDiv2;
3387 } else if (choice == _("Beats/3")) {
3388 snaptype = SnapToBeatDiv3;
3389 } else if (choice == _("Beats/4")) {
3390 snaptype = SnapToBeatDiv4;
3391 } else if (choice == _("Beats/5")) {
3392 snaptype = SnapToBeatDiv5;
3393 } else if (choice == _("Beats/6")) {
3394 snaptype = SnapToBeatDiv6;
3395 } else if (choice == _("Beats/7")) {
3396 snaptype = SnapToBeatDiv7;
3397 } else if (choice == _("Beats/8")) {
3398 snaptype = SnapToBeatDiv8;
3399 } else if (choice == _("Beats/10")) {
3400 snaptype = SnapToBeatDiv10;
3401 } else if (choice == _("Beats/12")) {
3402 snaptype = SnapToBeatDiv12;
3403 } else if (choice == _("Beats/14")) {
3404 snaptype = SnapToBeatDiv14;
3405 } else if (choice == _("Beats/16")) {
3406 snaptype = SnapToBeatDiv16;
3407 } else if (choice == _("Beats/20")) {
3408 snaptype = SnapToBeatDiv20;
3409 } else if (choice == _("Beats/24")) {
3410 snaptype = SnapToBeatDiv24;
3411 } else if (choice == _("Beats/28")) {
3412 snaptype = SnapToBeatDiv28;
3413 } else if (choice == _("Beats/32")) {
3414 snaptype = SnapToBeatDiv32;
3415 } else if (choice == _("Beats/64")) {
3416 snaptype = SnapToBeatDiv64;
3417 } else if (choice == _("Beats/128")) {
3418 snaptype = SnapToBeatDiv128;
3419 } else if (choice == _("Beats")) {
3420 snaptype = SnapToBeat;
3421 } else if (choice == _("Bars")) {
3422 snaptype = SnapToBar;
3423 } else if (choice == _("Marks")) {
3424 snaptype = SnapToMark;
3425 } else if (choice == _("Region starts")) {
3426 snaptype = SnapToRegionStart;
3427 } else if (choice == _("Region ends")) {
3428 snaptype = SnapToRegionEnd;
3429 } else if (choice == _("Region bounds")) {
3430 snaptype = SnapToRegionBoundary;
3431 } else if (choice == _("Region syncs")) {
3432 snaptype = SnapToRegionSync;
3433 } else if (choice == _("CD Frames")) {
3434 snaptype = SnapToCDFrame;
3435 } else if (choice == _("Timecode Frames")) {
3436 snaptype = SnapToTimecodeFrame;
3437 } else if (choice == _("Timecode Seconds")) {
3438 snaptype = SnapToTimecodeSeconds;
3439 } else if (choice == _("Timecode Minutes")) {
3440 snaptype = SnapToTimecodeMinutes;
3441 } else if (choice == _("Seconds")) {
3442 snaptype = SnapToSeconds;
3443 } else if (choice == _("Minutes")) {
3444 snaptype = SnapToMinutes;
3447 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3449 ract->set_active ();
3454 Editor::snap_mode_selection_done ()
3456 string choice = snap_mode_selector.get_active_text();
3457 SnapMode mode = SnapNormal;
3459 if (choice == _("No Grid")) {
3461 } else if (choice == _("Grid")) {
3463 } else if (choice == _("Magnetic")) {
3464 mode = SnapMagnetic;
3467 RefPtr<RadioAction> ract = snap_mode_action (mode);
3470 ract->set_active (true);
3475 Editor::cycle_edit_point (bool with_marker)
3477 switch (_edit_point) {
3479 set_edit_point_preference (EditAtPlayhead);
3481 case EditAtPlayhead:
3483 set_edit_point_preference (EditAtSelectedMarker);
3485 set_edit_point_preference (EditAtMouse);
3488 case EditAtSelectedMarker:
3489 set_edit_point_preference (EditAtMouse);
3495 Editor::edit_point_selection_done ()
3497 string choice = edit_point_selector.get_active_text();
3498 EditPoint ep = EditAtSelectedMarker;
3500 if (choice == _("Marker")) {
3501 set_edit_point_preference (EditAtSelectedMarker);
3502 } else if (choice == _("Playhead")) {
3503 set_edit_point_preference (EditAtPlayhead);
3505 set_edit_point_preference (EditAtMouse);
3508 RefPtr<RadioAction> ract = edit_point_action (ep);
3511 ract->set_active (true);
3516 Editor::zoom_focus_selection_done ()
3518 string choice = zoom_focus_selector.get_active_text();
3519 ZoomFocus focus_type = ZoomFocusLeft;
3521 if (choice == _("Left")) {
3522 focus_type = ZoomFocusLeft;
3523 } else if (choice == _("Right")) {
3524 focus_type = ZoomFocusRight;
3525 } else if (choice == _("Center")) {
3526 focus_type = ZoomFocusCenter;
3527 } else if (choice == _("Playhead")) {
3528 focus_type = ZoomFocusPlayhead;
3529 } else if (choice == _("Mouse")) {
3530 focus_type = ZoomFocusMouse;
3531 } else if (choice == _("Edit point")) {
3532 focus_type = ZoomFocusEdit;
3535 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3538 ract->set_active ();
3543 Editor::edit_controls_button_release (GdkEventButton* ev)
3545 if (Keyboard::is_context_menu_event (ev)) {
3546 ARDOUR_UI::instance()->add_route (this);
3547 } else if (ev->button == 1) {
3548 selection->clear_tracks ();
3555 Editor::mouse_select_button_release (GdkEventButton* ev)
3557 /* this handles just right-clicks */
3559 if (ev->button != 3) {
3567 Editor::set_zoom_focus (ZoomFocus f)
3569 string str = zoom_focus_strings[(int)f];
3571 if (str != zoom_focus_selector.get_active_text()) {
3572 zoom_focus_selector.set_active_text (str);
3575 if (zoom_focus != f) {
3582 Editor::cycle_zoom_focus ()
3584 switch (zoom_focus) {
3586 set_zoom_focus (ZoomFocusRight);
3588 case ZoomFocusRight:
3589 set_zoom_focus (ZoomFocusCenter);
3591 case ZoomFocusCenter:
3592 set_zoom_focus (ZoomFocusPlayhead);
3594 case ZoomFocusPlayhead:
3595 set_zoom_focus (ZoomFocusMouse);
3597 case ZoomFocusMouse:
3598 set_zoom_focus (ZoomFocusEdit);
3601 set_zoom_focus (ZoomFocusLeft);
3607 Editor::ensure_float (Window& win)
3609 win.set_transient_for (*this);
3613 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3615 /* recover or initialize pane positions. do this here rather than earlier because
3616 we don't want the positions to change the child allocations, which they seem to do.
3622 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3631 XMLNode* geometry = find_named_node (*node, "geometry");
3633 if (which == static_cast<Paned*> (&edit_pane)) {
3635 if (done & Horizontal) {
3639 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3640 _notebook_shrunk = string_is_affirmative (prop->value ());
3643 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3644 /* initial allocation is 90% to canvas, 10% to notebook */
3645 pos = (int) floor (alloc.get_width() * 0.90f);
3646 snprintf (buf, sizeof(buf), "%d", pos);
3648 pos = atoi (prop->value());
3651 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3652 edit_pane.set_position (pos);
3655 done = (Pane) (done | Horizontal);
3657 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3659 if (done & Vertical) {
3663 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3664 /* initial allocation is 90% to canvas, 10% to summary */
3665 pos = (int) floor (alloc.get_height() * 0.90f);
3666 snprintf (buf, sizeof(buf), "%d", pos);
3669 pos = atoi (prop->value());
3672 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3673 editor_summary_pane.set_position (pos);
3676 done = (Pane) (done | Vertical);
3681 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3683 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3684 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3685 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3686 top_hbox.remove (toolbar_frame);
3691 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3693 if (toolbar_frame.get_parent() == 0) {
3694 top_hbox.pack_end (toolbar_frame);
3699 Editor::set_show_measures (bool yn)
3701 if (_show_measures != yn) {
3704 if ((_show_measures = yn) == true) {
3706 tempo_lines->show();
3708 (void) redraw_measures ();
3715 Editor::toggle_follow_playhead ()
3717 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3719 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3720 set_follow_playhead (tact->get_active());
3724 /** @param yn true to follow playhead, otherwise false.
3725 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3728 Editor::set_follow_playhead (bool yn, bool catch_up)
3730 if (_follow_playhead != yn) {
3731 if ((_follow_playhead = yn) == true && catch_up) {
3733 reset_x_origin_to_follow_playhead ();
3740 Editor::toggle_stationary_playhead ()
3742 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3744 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3745 set_stationary_playhead (tact->get_active());
3750 Editor::set_stationary_playhead (bool yn)
3752 if (_stationary_playhead != yn) {
3753 if ((_stationary_playhead = yn) == true) {
3755 // FIXME need a 3.0 equivalent of this 2.X call
3756 // update_current_screen ();
3763 Editor::playlist_selector () const
3765 return *_playlist_selector;
3769 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3773 switch (_snap_type) {
3778 case SnapToBeatDiv128:
3781 case SnapToBeatDiv64:
3784 case SnapToBeatDiv32:
3787 case SnapToBeatDiv28:
3790 case SnapToBeatDiv24:
3793 case SnapToBeatDiv20:
3796 case SnapToBeatDiv16:
3799 case SnapToBeatDiv14:
3802 case SnapToBeatDiv12:
3805 case SnapToBeatDiv10:
3808 case SnapToBeatDiv8:
3811 case SnapToBeatDiv7:
3814 case SnapToBeatDiv6:
3817 case SnapToBeatDiv5:
3820 case SnapToBeatDiv4:
3823 case SnapToBeatDiv3:
3826 case SnapToBeatDiv2:
3832 return _session->tempo_map().meter_at (position).divisions_per_bar();
3837 case SnapToTimecodeFrame:
3838 case SnapToTimecodeSeconds:
3839 case SnapToTimecodeMinutes:
3842 case SnapToRegionStart:
3843 case SnapToRegionEnd:
3844 case SnapToRegionSync:
3845 case SnapToRegionBoundary:
3855 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3859 ret = nudge_clock->current_duration (pos);
3860 next = ret + 1; /* XXXX fix me */
3866 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3868 ArdourDialog dialog (_("Playlist Deletion"));
3869 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3870 "If it is kept, its audio files will not be cleaned.\n"
3871 "If it is deleted, audio files used by it alone will be cleaned."),
3874 dialog.set_position (WIN_POS_CENTER);
3875 dialog.get_vbox()->pack_start (label);
3879 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3880 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3881 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3883 switch (dialog.run ()) {
3884 case RESPONSE_ACCEPT:
3885 /* delete the playlist */
3889 case RESPONSE_REJECT:
3890 /* keep the playlist */
3902 Editor::audio_region_selection_covers (framepos_t where)
3904 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3905 if ((*a)->region()->covers (where)) {
3914 Editor::prepare_for_cleanup ()
3916 cut_buffer->clear_regions ();
3917 cut_buffer->clear_playlists ();
3919 selection->clear_regions ();
3920 selection->clear_playlists ();
3922 _regions->suspend_redisplay ();
3926 Editor::finish_cleanup ()
3928 _regions->resume_redisplay ();
3932 Editor::transport_loop_location()
3935 return _session->locations()->auto_loop_location();
3942 Editor::transport_punch_location()
3945 return _session->locations()->auto_punch_location();
3952 Editor::control_layout_scroll (GdkEventScroll* ev)
3954 if (Keyboard::some_magic_widget_has_focus()) {
3958 switch (ev->direction) {
3960 scroll_tracks_up_line ();
3964 case GDK_SCROLL_DOWN:
3965 scroll_tracks_down_line ();
3969 /* no left/right handling yet */
3977 Editor::session_state_saved (string)
3980 _snapshots->redisplay ();
3984 Editor::update_tearoff_visibility()
3986 bool visible = Config->get_keep_tearoffs();
3987 _mouse_mode_tearoff->set_visible (visible);
3988 _tools_tearoff->set_visible (visible);
3989 _zoom_tearoff->set_visible (visible);
3993 Editor::maximise_editing_space ()
4005 Editor::restore_editing_space ()
4017 * Make new playlists for a given track and also any others that belong
4018 * to the same active route group with the `select' property.
4023 Editor::new_playlists (TimeAxisView* v)
4025 begin_reversible_command (_("new playlists"));
4026 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4027 _session->playlists->get (playlists);
4028 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4029 commit_reversible_command ();
4033 * Use a copy of the current playlist for a given track and also any others that belong
4034 * to the same active route group with the `select' property.
4039 Editor::copy_playlists (TimeAxisView* v)
4041 begin_reversible_command (_("copy playlists"));
4042 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4043 _session->playlists->get (playlists);
4044 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4045 commit_reversible_command ();
4048 /** Clear the current playlist for a given track and also any others that belong
4049 * to the same active route group with the `select' property.
4054 Editor::clear_playlists (TimeAxisView* v)
4056 begin_reversible_command (_("clear playlists"));
4057 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4058 _session->playlists->get (playlists);
4059 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4060 commit_reversible_command ();
4064 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4066 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4070 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4072 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4076 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4078 atv.clear_playlist ();
4082 Editor::on_key_press_event (GdkEventKey* ev)
4084 return key_press_focus_accelerator_handler (*this, ev);
4088 Editor::on_key_release_event (GdkEventKey* ev)
4090 return Gtk::Window::on_key_release_event (ev);
4091 // return key_press_focus_accelerator_handler (*this, ev);
4094 /** Queue up a change to the viewport x origin.
4095 * @param frame New x origin.
4098 Editor::reset_x_origin (framepos_t frame)
4100 pending_visual_change.add (VisualChange::TimeOrigin);
4101 pending_visual_change.time_origin = frame;
4102 ensure_visual_change_idle_handler ();
4106 Editor::reset_y_origin (double y)
4108 pending_visual_change.add (VisualChange::YOrigin);
4109 pending_visual_change.y_origin = y;
4110 ensure_visual_change_idle_handler ();
4114 Editor::reset_zoom (double fpu)
4116 clamp_frames_per_unit (fpu);
4118 if (fpu == frames_per_unit) {
4122 pending_visual_change.add (VisualChange::ZoomLevel);
4123 pending_visual_change.frames_per_unit = fpu;
4124 ensure_visual_change_idle_handler ();
4128 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4130 reset_x_origin (frame);
4133 if (!no_save_visual) {
4134 undo_visual_stack.push_back (current_visual_state(false));
4138 Editor::VisualState::VisualState (bool with_tracks)
4139 : gui_state (with_tracks ? new GUIObjectState : 0)
4143 Editor::VisualState::~VisualState ()
4148 Editor::VisualState*
4149 Editor::current_visual_state (bool with_tracks)
4151 VisualState* vs = new VisualState (with_tracks);
4152 vs->y_position = vertical_adjustment.get_value();
4153 vs->frames_per_unit = frames_per_unit;
4154 vs->leftmost_frame = leftmost_frame;
4155 vs->zoom_focus = zoom_focus;
4158 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4165 Editor::undo_visual_state ()
4167 if (undo_visual_stack.empty()) {
4171 VisualState* vs = undo_visual_stack.back();
4172 undo_visual_stack.pop_back();
4175 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4177 use_visual_state (*vs);
4181 Editor::redo_visual_state ()
4183 if (redo_visual_stack.empty()) {
4187 VisualState* vs = redo_visual_stack.back();
4188 redo_visual_stack.pop_back();
4190 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4192 use_visual_state (*vs);
4196 Editor::swap_visual_state ()
4198 if (undo_visual_stack.empty()) {
4199 redo_visual_state ();
4201 undo_visual_state ();
4206 Editor::use_visual_state (VisualState& vs)
4208 PBD::Unwinder<bool> nsv (no_save_visual, true);
4210 _routes->suspend_redisplay ();
4212 vertical_adjustment.set_value (vs.y_position);
4214 set_zoom_focus (vs.zoom_focus);
4215 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4218 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4220 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4221 (*i)->reset_visual_state ();
4225 _routes->update_visibility ();
4226 _routes->resume_redisplay ();
4229 /** This is the core function that controls the zoom level of the canvas. It is called
4230 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4231 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4234 Editor::set_frames_per_unit (double fpu)
4237 tempo_lines->tempo_map_changed();
4240 frames_per_unit = fpu;
4242 /* convert fpu to frame count */
4244 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4246 if (frames_per_unit != zoom_range_clock->current_duration()) {
4247 zoom_range_clock->set (frames);
4250 bool const showing_time_selection = selection->time.length() > 0;
4252 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4253 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4254 (*i)->reshow_selection (selection->time);
4258 ZoomChanged (); /* EMIT_SIGNAL */
4260 //reset_scrolling_region ();
4262 if (playhead_cursor) {
4263 playhead_cursor->set_position (playhead_cursor->current_frame);
4266 refresh_location_display();
4267 _summary->set_overlays_dirty ();
4269 update_marker_labels ();
4275 Editor::queue_visual_videotimeline_update ()
4278 * pending_visual_change.add (VisualChange::VideoTimeline);
4279 * or maybe even more specific: which videotimeline-image
4280 * currently it calls update_video_timeline() to update
4281 * _all outdated_ images on the video-timeline.
4282 * see 'exposeimg()' in video_image_frame.cc
4284 ensure_visual_change_idle_handler ();
4288 Editor::ensure_visual_change_idle_handler ()
4290 if (pending_visual_change.idle_handler_id < 0) {
4291 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4296 Editor::_idle_visual_changer (void* arg)
4298 return static_cast<Editor*>(arg)->idle_visual_changer ();
4302 Editor::idle_visual_changer ()
4304 /* set_horizontal_position() below (and maybe other calls) call
4305 gtk_main_iteration(), so it's possible that a signal will be handled
4306 half-way through this method. If this signal wants an
4307 idle_visual_changer we must schedule another one after this one, so
4308 mark the idle_handler_id as -1 here to allow that. Also make a note
4309 that we are doing the visual change, so that changes in response to
4310 super-rapid-screen-update can be dropped if we are still processing
4314 pending_visual_change.idle_handler_id = -1;
4315 pending_visual_change.being_handled = true;
4317 VisualChange::Type p = pending_visual_change.pending;
4318 pending_visual_change.pending = (VisualChange::Type) 0;
4320 double const last_time_origin = horizontal_position ();
4322 if (p & VisualChange::ZoomLevel) {
4323 set_frames_per_unit (pending_visual_change.frames_per_unit);
4325 compute_fixed_ruler_scale ();
4327 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4328 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4330 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4331 current_bbt_points_begin, current_bbt_points_end);
4332 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4333 current_bbt_points_begin, current_bbt_points_end);
4334 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4337 if (p & VisualChange::ZoomLevel) {
4338 update_video_timeline();
4341 if (p & VisualChange::TimeOrigin) {
4342 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4345 if (p & VisualChange::YOrigin) {
4346 vertical_adjustment.set_value (pending_visual_change.y_origin);
4349 if (last_time_origin == horizontal_position ()) {
4350 /* changed signal not emitted */
4351 update_fixed_rulers ();
4352 redisplay_tempo (true);
4355 if (!(p & VisualChange::ZoomLevel)) {
4356 update_video_timeline();
4359 _summary->set_overlays_dirty ();
4361 pending_visual_change.being_handled = false;
4362 return 0; /* this is always a one-shot call */
4365 struct EditorOrderTimeAxisSorter {
4366 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4367 return a->order () < b->order ();
4372 Editor::sort_track_selection (TrackViewList& sel)
4374 EditorOrderTimeAxisSorter cmp;
4379 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4382 framepos_t where = 0;
4383 EditPoint ep = _edit_point;
4385 if (from_context_menu && (ep == EditAtMouse)) {
4386 return event_frame (&context_click_event, 0, 0);
4389 if (entered_marker) {
4390 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4391 return entered_marker->position();
4394 if (ignore_playhead && ep == EditAtPlayhead) {
4395 ep = EditAtSelectedMarker;
4399 case EditAtPlayhead:
4400 where = _session->audible_frame();
4401 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4404 case EditAtSelectedMarker:
4405 if (!selection->markers.empty()) {
4407 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4410 where = loc->start();
4414 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4422 if (!mouse_frame (where, ignored)) {
4423 /* XXX not right but what can we do ? */
4427 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4435 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4437 if (!_session) return;
4439 begin_reversible_command (cmd);
4443 if ((tll = transport_loop_location()) == 0) {
4444 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4445 XMLNode &before = _session->locations()->get_state();
4446 _session->locations()->add (loc, true);
4447 _session->set_auto_loop_location (loc);
4448 XMLNode &after = _session->locations()->get_state();
4449 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4451 XMLNode &before = tll->get_state();
4452 tll->set_hidden (false, this);
4453 tll->set (start, end);
4454 XMLNode &after = tll->get_state();
4455 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4458 commit_reversible_command ();
4462 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4464 if (!_session) return;
4466 begin_reversible_command (cmd);
4470 if ((tpl = transport_punch_location()) == 0) {
4471 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4472 XMLNode &before = _session->locations()->get_state();
4473 _session->locations()->add (loc, true);
4474 _session->set_auto_loop_location (loc);
4475 XMLNode &after = _session->locations()->get_state();
4476 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4479 XMLNode &before = tpl->get_state();
4480 tpl->set_hidden (false, this);
4481 tpl->set (start, end);
4482 XMLNode &after = tpl->get_state();
4483 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4486 commit_reversible_command ();
4489 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4490 * @param rs List to which found regions are added.
4491 * @param where Time to look at.
4492 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4495 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4497 const TrackViewList* tracks;
4500 tracks = &track_views;
4505 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4507 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4510 boost::shared_ptr<Track> tr;
4511 boost::shared_ptr<Playlist> pl;
4513 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4515 boost::shared_ptr<RegionList> regions = pl->regions_at (
4516 (framepos_t) floor ( (double) where * tr->speed()));
4518 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4519 RegionView* rv = rtv->view()->find_view (*i);
4530 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4532 const TrackViewList* tracks;
4535 tracks = &track_views;
4540 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4541 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4543 boost::shared_ptr<Track> tr;
4544 boost::shared_ptr<Playlist> pl;
4546 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4548 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4549 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4551 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4553 RegionView* rv = rtv->view()->find_view (*i);
4564 /** Get regions using the following method:
4566 * Make a region list using the selected regions, unless
4567 * the edit point is `mouse' and the mouse is over an unselected
4568 * region. In this case, use just that region.
4570 * If the edit point is not 'mouse', and there are no regions selected,
4571 * search the list of selected tracks and return regions that are under
4572 * the edit point on these tracks. If there are no selected tracks and
4573 * 'No Selection = All Tracks' is active, search all tracks,
4575 * The rationale here is that the mouse edit point is special in that
4576 * its position describes both a time and a track; the other edit
4577 * modes only describe a time. Hence if the edit point is `mouse' we
4578 * ignore selected tracks, as we assume the user means something by
4579 * pointing at a particular track. Also in this case we take note of
4580 * the region directly under the edit point, as there is always just one
4581 * (rather than possibly several with non-mouse edit points).
4585 Editor::get_regions_from_selection_and_edit_point ()
4587 RegionSelection regions;
4589 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4590 regions.add (entered_regionview);
4592 regions = selection->regions;
4596 if (regions.empty() && _edit_point != EditAtMouse) {
4597 TrackViewList tracks = selection->tracks;
4599 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4600 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4601 * is enabled, so consider all tracks
4603 tracks = track_views;
4606 if (!tracks.empty()) {
4607 /* no region selected or entered, but some selected tracks:
4608 * act on all regions on the selected tracks at the edit point
4610 framepos_t const where = get_preferred_edit_position ();
4611 get_regions_at(regions, where, tracks);
4617 /** Start with regions that are selected, or the entered regionview if none are selected.
4618 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4619 * of the regions that we started with.
4623 Editor::get_regions_from_selection_and_entered ()
4625 RegionSelection regions = selection->regions;
4627 if (regions.empty() && entered_regionview) {
4628 regions.add (entered_regionview);
4635 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4637 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4639 RouteTimeAxisView* tatv;
4641 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4643 boost::shared_ptr<Playlist> pl;
4644 vector<boost::shared_ptr<Region> > results;
4646 boost::shared_ptr<Track> tr;
4648 if ((tr = tatv->track()) == 0) {
4653 if ((pl = (tr->playlist())) != 0) {
4654 if (src_comparison) {
4655 pl->get_source_equivalent_regions (region, results);
4657 pl->get_region_list_equivalent_regions (region, results);
4661 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4662 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4663 regions.push_back (marv);
4672 Editor::show_rhythm_ferret ()
4674 if (rhythm_ferret == 0) {
4675 rhythm_ferret = new RhythmFerret(*this);
4678 rhythm_ferret->set_session (_session);
4679 rhythm_ferret->show ();
4680 rhythm_ferret->present ();
4684 Editor::first_idle ()
4686 MessageDialog* dialog = 0;
4688 if (track_views.size() > 1) {
4689 dialog = new MessageDialog (
4691 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4695 ARDOUR_UI::instance()->flush_pending ();
4698 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4702 // first idle adds route children (automation tracks), so we need to redisplay here
4703 _routes->redisplay ();
4710 Editor::_idle_resize (gpointer arg)
4712 return ((Editor*)arg)->idle_resize ();
4716 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4718 if (resize_idle_id < 0) {
4719 resize_idle_id = g_idle_add (_idle_resize, this);
4720 _pending_resize_amount = 0;
4723 /* make a note of the smallest resulting height, so that we can clamp the
4724 lower limit at TimeAxisView::hSmall */
4726 int32_t min_resulting = INT32_MAX;
4728 _pending_resize_amount += h;
4729 _pending_resize_view = view;
4731 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4733 if (selection->tracks.contains (_pending_resize_view)) {
4734 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4735 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4739 if (min_resulting < 0) {
4744 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4745 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4749 /** Handle pending resizing of tracks */
4751 Editor::idle_resize ()
4753 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4755 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4756 selection->tracks.contains (_pending_resize_view)) {
4758 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4759 if (*i != _pending_resize_view) {
4760 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4765 _pending_resize_amount = 0;
4767 _group_tabs->set_dirty ();
4768 resize_idle_id = -1;
4776 ENSURE_GUI_THREAD (*this, &Editor::located);
4779 playhead_cursor->set_position (_session->audible_frame ());
4780 if (_follow_playhead && !_pending_initial_locate) {
4781 reset_x_origin_to_follow_playhead ();
4785 _pending_locate_request = false;
4786 _pending_initial_locate = false;
4790 Editor::region_view_added (RegionView *)
4792 _summary->set_dirty ();
4796 Editor::region_view_removed ()
4798 _summary->set_dirty ();
4802 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4804 TrackViewList::const_iterator j = track_views.begin ();
4805 while (j != track_views.end()) {
4806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4807 if (rtv && rtv->route() == r) {
4818 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4822 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4823 TimeAxisView* tv = axis_view_from_route (*i);
4833 Editor::add_routes (RouteList& routes)
4835 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4837 RouteTimeAxisView *rtv;
4838 list<RouteTimeAxisView*> new_views;
4840 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4841 boost::shared_ptr<Route> route = (*x);
4843 if (route->is_auditioner() || route->is_monitor()) {
4847 DataType dt = route->input()->default_type();
4849 if (dt == ARDOUR::DataType::AUDIO) {
4850 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4851 rtv->set_route (route);
4852 } else if (dt == ARDOUR::DataType::MIDI) {
4853 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4854 rtv->set_route (route);
4856 throw unknown_type();
4859 new_views.push_back (rtv);
4860 track_views.push_back (rtv);
4862 rtv->effective_gain_display ();
4864 if (internal_editing()) {
4865 rtv->enter_internal_edit_mode ();
4867 rtv->leave_internal_edit_mode ();
4870 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4871 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4874 _routes->routes_added (new_views);
4875 _summary->routes_added (new_views);
4877 if (show_editor_mixer_when_tracks_arrive) {
4878 show_editor_mixer (true);
4881 editor_list_button.set_sensitive (true);
4885 Editor::timeaxisview_deleted (TimeAxisView *tv)
4887 if (_session && _session->deletion_in_progress()) {
4888 /* the situation is under control */
4892 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4894 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4896 _routes->route_removed (tv);
4898 if (tv == entered_track) {
4902 TimeAxisView::Children c = tv->get_child_list ();
4903 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4904 if (entered_track == i->get()) {
4909 /* remove it from the list of track views */
4911 TrackViewList::iterator i;
4913 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4914 i = track_views.erase (i);
4917 /* update whatever the current mixer strip is displaying, if revelant */
4919 boost::shared_ptr<Route> route;
4922 route = rtav->route ();
4925 if (current_mixer_strip && current_mixer_strip->route() == route) {
4927 TimeAxisView* next_tv;
4929 if (track_views.empty()) {
4931 } else if (i == track_views.end()) {
4932 next_tv = track_views.front();
4939 set_selected_mixer_strip (*next_tv);
4941 /* make the editor mixer strip go away setting the
4942 * button to inactive (which also unticks the menu option)
4945 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4951 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4953 if (apply_to_selection) {
4954 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4956 TrackSelection::iterator j = i;
4959 hide_track_in_display (*i, false);
4964 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4966 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4967 // this will hide the mixer strip
4968 set_selected_mixer_strip (*tv);
4971 _routes->hide_track_in_display (*tv);
4976 Editor::sync_track_view_list_and_routes ()
4978 track_views = TrackViewList (_routes->views ());
4980 _summary->set_dirty ();
4981 _group_tabs->set_dirty ();
4983 return false; // do not call again (until needed)
4987 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4989 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4994 /** Find a RouteTimeAxisView by the ID of its route */
4996 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4998 RouteTimeAxisView* v;
5000 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5001 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5002 if(v->route()->id() == id) {
5012 Editor::fit_route_group (RouteGroup *g)
5014 TrackViewList ts = axis_views_from_routes (g->route_list ());
5019 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5021 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5024 _session->cancel_audition ();
5028 if (_session->is_auditioning()) {
5029 _session->cancel_audition ();
5030 if (r == last_audition_region) {
5035 _session->audition_region (r);
5036 last_audition_region = r;
5041 Editor::hide_a_region (boost::shared_ptr<Region> r)
5043 r->set_hidden (true);
5047 Editor::show_a_region (boost::shared_ptr<Region> r)
5049 r->set_hidden (false);
5053 Editor::audition_region_from_region_list ()
5055 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5059 Editor::hide_region_from_region_list ()
5061 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5065 Editor::show_region_in_region_list ()
5067 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5071 Editor::step_edit_status_change (bool yn)
5074 start_step_editing ();
5076 stop_step_editing ();
5081 Editor::start_step_editing ()
5083 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5087 Editor::stop_step_editing ()
5089 step_edit_connection.disconnect ();
5093 Editor::check_step_edit ()
5095 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5096 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5098 mtv->check_step_edit ();
5102 return true; // do it again, till we stop
5106 Editor::scroll_press (Direction dir)
5108 ++_scroll_callbacks;
5110 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5111 /* delay the first auto-repeat */
5117 scroll_backward (1);
5125 scroll_tracks_up_line ();
5129 scroll_tracks_down_line ();
5133 /* do hacky auto-repeat */
5134 if (!_scroll_connection.connected ()) {
5136 _scroll_connection = Glib::signal_timeout().connect (
5137 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5140 _scroll_callbacks = 0;
5147 Editor::scroll_release ()
5149 _scroll_connection.disconnect ();
5152 /** Queue a change for the Editor viewport x origin to follow the playhead */
5154 Editor::reset_x_origin_to_follow_playhead ()
5156 framepos_t const frame = playhead_cursor->current_frame;
5158 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5160 if (_session->transport_speed() < 0) {
5162 if (frame > (current_page_frames() / 2)) {
5163 center_screen (frame-(current_page_frames()/2));
5165 center_screen (current_page_frames()/2);
5172 if (frame < leftmost_frame) {
5174 if (_session->transport_rolling()) {
5175 /* rolling; end up with the playhead at the right of the page */
5176 l = frame - current_page_frames ();
5178 /* not rolling: end up with the playhead 1/4 of the way along the page */
5179 l = frame - current_page_frames() / 4;
5183 if (_session->transport_rolling()) {
5184 /* rolling: end up with the playhead on the left of the page */
5187 /* not rolling: end up with the playhead 3/4 of the way along the page */
5188 l = frame - 3 * current_page_frames() / 4;
5196 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5202 Editor::super_rapid_screen_update ()
5204 if (!_session || !_session->engine().running()) {
5208 /* METERING / MIXER STRIPS */
5210 /* update track meters, if required */
5211 if (is_mapped() && meters_running) {
5212 RouteTimeAxisView* rtv;
5213 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5214 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5215 rtv->fast_update ();
5220 /* and any current mixer strip */
5221 if (current_mixer_strip) {
5222 current_mixer_strip->fast_update ();
5225 /* PLAYHEAD AND VIEWPORT */
5227 framepos_t const frame = _session->audible_frame();
5229 /* There are a few reasons why we might not update the playhead / viewport stuff:
5231 * 1. we don't update things when there's a pending locate request, otherwise
5232 * when the editor requests a locate there is a chance that this method
5233 * will move the playhead before the locate request is processed, causing
5235 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5236 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5239 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5241 last_update_frame = frame;
5243 if (!_dragging_playhead) {
5244 playhead_cursor->set_position (frame);
5247 if (!_stationary_playhead) {
5249 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5250 /* We only do this if we aren't already
5251 handling a visual change (ie if
5252 pending_visual_change.being_handled is
5253 false) so that these requests don't stack
5254 up there are too many of them to handle in
5257 reset_x_origin_to_follow_playhead ();
5262 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5266 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5267 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5268 if (target <= 0.0) {
5271 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5272 target = (target * 0.15) + (current * 0.85);
5278 set_horizontal_position (current);
5287 Editor::session_going_away ()
5289 _have_idled = false;
5291 _session_connections.drop_connections ();
5293 super_rapid_screen_update_connection.disconnect ();
5295 selection->clear ();
5296 cut_buffer->clear ();
5298 clicked_regionview = 0;
5299 clicked_axisview = 0;
5300 clicked_routeview = 0;
5301 entered_regionview = 0;
5303 last_update_frame = 0;
5306 playhead_cursor->canvas_item.hide ();
5308 /* rip everything out of the list displays */
5312 _route_groups->clear ();
5314 /* do this first so that deleting a track doesn't reset cms to null
5315 and thus cause a leak.
5318 if (current_mixer_strip) {
5319 if (current_mixer_strip->get_parent() != 0) {
5320 global_hpacker.remove (*current_mixer_strip);
5322 delete current_mixer_strip;
5323 current_mixer_strip = 0;
5326 /* delete all trackviews */
5328 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5331 track_views.clear ();
5333 zoom_range_clock->set_session (0);
5334 nudge_clock->set_session (0);
5336 editor_list_button.set_active(false);
5337 editor_list_button.set_sensitive(false);
5339 /* clear tempo/meter rulers */
5340 remove_metric_marks ();
5342 clear_marker_display ();
5344 stop_step_editing ();
5346 /* get rid of any existing editor mixer strip */
5348 WindowTitle title(Glib::get_application_name());
5349 title += _("Editor");
5351 set_title (title.get_string());
5353 SessionHandlePtr::session_going_away ();
5358 Editor::show_editor_list (bool yn)
5361 _the_notebook.show ();
5363 _the_notebook.hide ();
5368 Editor::change_region_layering_order (bool from_context_menu)
5370 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5372 if (!clicked_routeview) {
5373 if (layering_order_editor) {
5374 layering_order_editor->hide ();
5379 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5385 boost::shared_ptr<Playlist> pl = track->playlist();
5391 if (layering_order_editor == 0) {
5392 layering_order_editor = new RegionLayeringOrderEditor (*this);
5395 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5396 layering_order_editor->maybe_present ();
5400 Editor::update_region_layering_order_editor ()
5402 if (layering_order_editor && layering_order_editor->is_visible ()) {
5403 change_region_layering_order (true);
5408 Editor::setup_fade_images ()
5410 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5411 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5412 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5413 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5414 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5416 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5417 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5418 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5419 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5420 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5422 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5423 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5424 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5425 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5426 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5428 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5429 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5430 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5431 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5432 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5436 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5438 Editor::action_menu_item (std::string const & name)
5440 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5443 return *manage (a->create_menu_item ());
5447 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5449 EventBox* b = manage (new EventBox);
5450 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5451 Label* l = manage (new Label (name));
5455 _the_notebook.append_page (widget, *b);
5459 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5461 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5462 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5465 if (ev->type == GDK_2BUTTON_PRESS) {
5467 /* double-click on a notebook tab shrinks or expands the notebook */
5469 if (_notebook_shrunk) {
5470 if (pre_notebook_shrink_pane_width) {
5471 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5473 _notebook_shrunk = false;
5475 pre_notebook_shrink_pane_width = edit_pane.get_position();
5477 /* this expands the LHS of the edit pane to cover the notebook
5478 PAGE but leaves the tabs visible.
5480 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5481 _notebook_shrunk = true;
5489 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5491 using namespace Menu_Helpers;
5493 MenuList& items = _control_point_context_menu.items ();
5496 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5497 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5498 if (!can_remove_control_point (item)) {
5499 items.back().set_sensitive (false);
5502 _control_point_context_menu.popup (event->button.button, event->button.time);
5506 Editor::zoom_vertical_modifier_released()
5508 _stepping_axis_view = 0;