2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , videotl_label (_("Video Timeline"))
250 , edit_packer (4, 4, true)
252 /* the values here don't matter: layout widgets
253 reset them as needed.
256 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
258 /* tool bar related */
260 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
262 , toolbar_selection_clock_table (2,3)
264 , automation_mode_button (_("mode"))
266 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
269 , image_socket_listener(0)
274 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
275 , meters_running(false)
276 , _pending_locate_request (false)
277 , _pending_initial_locate (false)
278 , _last_cut_copy_source_track (0)
280 , _region_selection_change_updates_region_list (true)
281 , _following_mixer_selection (false)
282 , _control_point_toggled_on_press (false)
283 , _stepping_axis_view (0)
287 /* we are a singleton */
289 PublicEditor::_instance = this;
293 selection = new Selection (this);
294 cut_buffer = new Selection (this);
296 clicked_regionview = 0;
297 clicked_axisview = 0;
298 clicked_routeview = 0;
299 clicked_control_point = 0;
300 last_update_frame = 0;
301 pre_press_cursor = 0;
302 _drags = new DragManager (this);
303 current_mixer_strip = 0;
306 snap_type_strings = I18N (_snap_type_strings);
307 snap_mode_strings = I18N (_snap_mode_strings);
308 zoom_focus_strings = I18N (_zoom_focus_strings);
309 edit_point_strings = I18N (_edit_point_strings);
310 #ifdef USE_RUBBERBAND
311 rb_opt_strings = I18N (_rb_opt_strings);
315 snap_threshold = 5.0;
316 bbt_beat_subdivision = 4;
317 _visible_canvas_width = 0;
318 _visible_canvas_height = 0;
319 last_autoscroll_x = 0;
320 last_autoscroll_y = 0;
321 autoscroll_active = false;
322 autoscroll_timeout_tag = -1;
327 current_interthread_info = 0;
328 _show_measures = true;
330 show_gain_after_trim = false;
332 have_pending_keyboard_selection = false;
333 _follow_playhead = true;
334 _stationary_playhead = false;
335 editor_ruler_menu = 0;
336 no_ruler_shown_update = false;
338 range_marker_menu = 0;
339 marker_menu_item = 0;
340 tempo_or_meter_marker_menu = 0;
341 transport_marker_menu = 0;
342 new_transport_marker_menu = 0;
343 editor_mixer_strip_width = Wide;
344 show_editor_mixer_when_tracks_arrive = false;
345 region_edit_menu_split_multichannel_item = 0;
346 region_edit_menu_split_item = 0;
349 current_stepping_trackview = 0;
351 entered_regionview = 0;
353 clear_entered_track = false;
356 button_release_can_deselect = true;
357 _dragging_playhead = false;
358 _dragging_edit_point = false;
359 select_new_marker = false;
361 layering_order_editor = 0;
362 no_save_visual = false;
364 within_track_canvas = false;
366 scrubbing_direction = 0;
370 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
371 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
372 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
373 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
374 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
376 _edit_point = EditAtMouse;
377 _internal_editing = false;
378 current_canvas_cursor = 0;
380 frames_per_pixel = 2048; /* too early to use reset_zoom () */
382 _scroll_callbacks = 0;
384 zoom_focus = ZoomFocusLeft;
385 set_zoom_focus (ZoomFocusLeft);
386 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
388 bbt_label.set_name ("EditorRulerLabel");
389 bbt_label.set_size_request (-1, (int)timebar_height);
390 bbt_label.set_alignment (1.0, 0.5);
391 bbt_label.set_padding (5,0);
393 bbt_label.set_no_show_all();
394 minsec_label.set_name ("EditorRulerLabel");
395 minsec_label.set_size_request (-1, (int)timebar_height);
396 minsec_label.set_alignment (1.0, 0.5);
397 minsec_label.set_padding (5,0);
398 minsec_label.hide ();
399 minsec_label.set_no_show_all();
400 timecode_label.set_name ("EditorRulerLabel");
401 timecode_label.set_size_request (-1, (int)timebar_height);
402 timecode_label.set_alignment (1.0, 0.5);
403 timecode_label.set_padding (5,0);
404 timecode_label.hide ();
405 timecode_label.set_no_show_all();
406 samples_label.set_name ("EditorRulerLabel");
407 samples_label.set_size_request (-1, (int)timebar_height);
408 samples_label.set_alignment (1.0, 0.5);
409 samples_label.set_padding (5,0);
410 samples_label.hide ();
411 samples_label.set_no_show_all();
413 tempo_label.set_name ("EditorRulerLabel");
414 tempo_label.set_size_request (-1, (int)timebar_height);
415 tempo_label.set_alignment (1.0, 0.5);
416 tempo_label.set_padding (5,0);
418 tempo_label.set_no_show_all();
420 meter_label.set_name ("EditorRulerLabel");
421 meter_label.set_size_request (-1, (int)timebar_height);
422 meter_label.set_alignment (1.0, 0.5);
423 meter_label.set_padding (5,0);
425 meter_label.set_no_show_all();
427 mark_label.set_name ("EditorRulerLabel");
428 mark_label.set_size_request (-1, (int)timebar_height);
429 mark_label.set_alignment (1.0, 0.5);
430 mark_label.set_padding (5,0);
432 mark_label.set_no_show_all();
434 cd_mark_label.set_name ("EditorRulerLabel");
435 cd_mark_label.set_size_request (-1, (int)timebar_height);
436 cd_mark_label.set_alignment (1.0, 0.5);
437 cd_mark_label.set_padding (5,0);
438 cd_mark_label.hide();
439 cd_mark_label.set_no_show_all();
441 videotl_bar_height = 4;
442 videotl_label.set_name ("EditorRulerLabel");
443 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
444 videotl_label.set_alignment (1.0, 0.5);
445 videotl_label.set_padding (5,0);
446 videotl_label.hide();
447 videotl_label.set_no_show_all();
449 range_mark_label.set_name ("EditorRulerLabel");
450 range_mark_label.set_size_request (-1, (int)timebar_height);
451 range_mark_label.set_alignment (1.0, 0.5);
452 range_mark_label.set_padding (5,0);
453 range_mark_label.hide();
454 range_mark_label.set_no_show_all();
456 transport_mark_label.set_name ("EditorRulerLabel");
457 transport_mark_label.set_size_request (-1, (int)timebar_height);
458 transport_mark_label.set_alignment (1.0, 0.5);
459 transport_mark_label.set_padding (5,0);
460 transport_mark_label.hide();
461 transport_mark_label.set_no_show_all();
463 initialize_rulers ();
464 initialize_canvas ();
466 _summary = new EditorSummary (this);
468 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
469 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
471 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
473 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
474 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
476 edit_controls_vbox.set_spacing (0);
477 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
478 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
480 HBox* h = manage (new HBox);
481 _group_tabs = new EditorGroupTabs (this);
482 h->pack_start (*_group_tabs, PACK_SHRINK);
483 h->pack_start (edit_controls_vbox);
484 controls_layout.add (*h);
486 controls_layout.set_name ("EditControlsBase");
487 controls_layout.add_events (Gdk::SCROLL_MASK);
488 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
490 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
491 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
493 _cursors = new MouseCursors;
495 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
497 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
498 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
499 pad_line_1->set_outline_color (0xFF0000FF);
505 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
506 time_canvas_vbox.set_size_request (-1, -1);
508 ruler_label_event_box.add (ruler_label_vbox);
509 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_bars_event_box.add (time_bars_vbox);
513 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 time_canvas_event_box.add (time_canvas_vbox);
517 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
519 edit_packer.set_col_spacings (0);
520 edit_packer.set_row_spacings (0);
521 edit_packer.set_homogeneous (false);
522 edit_packer.set_border_width (0);
523 edit_packer.set_name ("EditorWindow");
525 /* labels for the rulers */
526 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
527 /* labels for the marker "tracks" (time bars) */
528 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
530 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
532 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
533 /* time bars canvas */
534 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
536 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
538 bottom_hbox.set_border_width (2);
539 bottom_hbox.set_spacing (3);
541 _route_groups = new EditorRouteGroups (this);
542 _routes = new EditorRoutes (this);
543 _regions = new EditorRegions (this);
544 _snapshots = new EditorSnapshots (this);
545 _locations = new EditorLocations (this);
547 add_notebook_page (_("Regions"), _regions->widget ());
548 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
549 add_notebook_page (_("Snapshots"), _snapshots->widget ());
550 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
551 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
553 _the_notebook.set_show_tabs (true);
554 _the_notebook.set_scrollable (true);
555 _the_notebook.popup_disable ();
556 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
557 _the_notebook.show_all ();
559 _notebook_shrunk = false;
561 editor_summary_pane.pack1(edit_packer);
563 Button* summary_arrows_left_left = manage (new Button);
564 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
565 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
566 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 Button* summary_arrows_left_right = manage (new Button);
569 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
570 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
571 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 VBox* summary_arrows_left = manage (new VBox);
574 summary_arrows_left->pack_start (*summary_arrows_left_left);
575 summary_arrows_left->pack_start (*summary_arrows_left_right);
577 Button* summary_arrows_right_up = manage (new Button);
578 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
579 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
580 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 Button* summary_arrows_right_down = manage (new Button);
583 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
584 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
585 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 VBox* summary_arrows_right = manage (new VBox);
588 summary_arrows_right->pack_start (*summary_arrows_right_up);
589 summary_arrows_right->pack_start (*summary_arrows_right_down);
591 Frame* summary_frame = manage (new Frame);
592 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
594 summary_frame->add (*_summary);
595 summary_frame->show ();
597 _summary_hbox.pack_start (*summary_arrows_left, false, false);
598 _summary_hbox.pack_start (*summary_frame, true, true);
599 _summary_hbox.pack_start (*summary_arrows_right, false, false);
601 editor_summary_pane.pack2 (_summary_hbox);
603 edit_pane.pack1 (editor_summary_pane, true, true);
604 edit_pane.pack2 (_the_notebook, false, true);
606 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
608 /* XXX: editor_summary_pane might need similar to the edit_pane */
610 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
612 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
615 top_hbox.pack_start (toolbar_frame);
617 HBox *hbox = manage (new HBox);
618 hbox->pack_start (edit_pane, true, true);
620 global_vpacker.pack_start (top_hbox, false, false);
621 global_vpacker.pack_start (*hbox, true, true);
623 global_hpacker.pack_start (global_vpacker, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager->get_accel_group());
628 status_bar_hpacker.show ();
630 vpacker.pack_end (status_bar_hpacker, false, false);
631 vpacker.pack_end (global_hpacker, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
636 /* when we start using our own keybinding system for the editor, this
637 * will be uncommented
643 _snap_type = SnapToBeat;
644 set_snap_to (_snap_type);
645 _snap_mode = SnapOff;
646 set_snap_mode (_snap_mode);
647 set_mouse_mode (MouseObject, true);
648 pre_internal_mouse_mode = MouseObject;
649 pre_internal_snap_type = _snap_type;
650 pre_internal_snap_mode = _snap_mode;
651 internal_snap_type = _snap_type;
652 internal_snap_mode = _snap_mode;
653 set_edit_point_preference (EditAtMouse, true);
655 _playlist_selector = new PlaylistSelector();
656 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
658 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
662 nudge_forward_button.set_name ("zoom button");
663 nudge_forward_button.add_elements (ArdourButton::FlatFace);
664 nudge_forward_button.set_image(::get_icon("nudge_right"));
666 nudge_backward_button.set_name ("zoom button");
667 nudge_backward_button.add_elements (ArdourButton::FlatFace);
668 nudge_backward_button.set_image(::get_icon("nudge_left"));
670 fade_context_menu.set_name ("ArdourContextMenu");
672 /* icons, titles, WM stuff */
674 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
675 Glib::RefPtr<Gdk::Pixbuf> icon;
677 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
684 window_icons.push_back (icon);
686 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
687 window_icons.push_back (icon);
689 if (!window_icons.empty()) {
690 // set_icon_list (window_icons);
691 set_default_icon_list (window_icons);
694 WindowTitle title(Glib::get_application_name());
695 title += _("Editor");
696 set_title (title.get_string());
697 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
700 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
702 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
703 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
705 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
707 /* allow external control surfaces/protocols to do various things */
709 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
710 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
711 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
712 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
713 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
714 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
715 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
716 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
717 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
718 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
719 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
720 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
721 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
722 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
724 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
725 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
726 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
727 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
728 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
730 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
732 /* problematic: has to return a value and thus cannot be x-thread */
734 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
736 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
738 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
740 _ignore_region_action = false;
741 _last_region_menu_was_main = false;
742 _popup_region_menu_item = 0;
744 _show_marker_lines = false;
745 _over_region_trim_target = false;
747 /* Button bindings */
749 button_bindings = new Bindings;
751 XMLNode* node = button_settings();
753 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
754 button_bindings->load (**i);
761 setup_fade_images ();
767 if(image_socket_listener) {
768 if(image_socket_listener->is_connected())
770 image_socket_listener->close_connection() ;
773 delete image_socket_listener ;
774 image_socket_listener = 0 ;
778 delete button_bindings;
780 delete _route_groups;
781 delete _time_bars_canvas_viewport;
782 delete _track_canvas_viewport;
787 Editor::button_settings () const
789 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
790 XMLNode* node = find_named_node (*settings, X_("Buttons"));
793 node = new XMLNode (X_("Buttons"));
800 Editor::add_toplevel_controls (Container& cont)
802 vpacker.pack_start (cont, false, false);
807 Editor::get_smart_mode () const
809 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
813 Editor::catch_vanishing_regionview (RegionView *rv)
815 /* note: the selection will take care of the vanishing
816 audioregionview by itself.
819 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
823 if (clicked_regionview == rv) {
824 clicked_regionview = 0;
827 if (entered_regionview == rv) {
828 set_entered_regionview (0);
831 if (!_all_region_actions_sensitized) {
832 sensitize_all_region_actions (true);
835 _over_region_trim_target = false;
839 Editor::set_entered_regionview (RegionView* rv)
841 if (rv == entered_regionview) {
845 if (entered_regionview) {
846 entered_regionview->exited ();
849 if ((entered_regionview = rv) != 0) {
850 entered_regionview->entered (internal_editing ());
853 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
854 /* This RegionView entry might have changed what region actions
855 are allowed, so sensitize them all in case a key is pressed.
857 sensitize_all_region_actions (true);
862 Editor::set_entered_track (TimeAxisView* tav)
865 entered_track->exited ();
868 if ((entered_track = tav) != 0) {
869 entered_track->entered ();
874 Editor::show_window ()
876 if (!is_visible ()) {
879 /* XXX: this is a bit unfortunate; it would probably
880 be nicer if we could just call show () above rather
881 than needing the show_all ()
884 /* re-hide stuff if necessary */
885 editor_list_button_toggled ();
886 parameter_changed ("show-summary");
887 parameter_changed ("show-group-tabs");
888 parameter_changed ("show-zoom-tools");
890 /* now reset all audio_time_axis heights, because widgets might need
896 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
897 tv = (static_cast<TimeAxisView*>(*i));
901 if (current_mixer_strip) {
902 current_mixer_strip->hide_things ();
903 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
911 Editor::instant_save ()
913 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
918 _session->add_instant_xml(get_state());
920 Config->add_instant_xml(get_state());
925 Editor::zoom_adjustment_changed ()
931 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
932 bool clamped = clamp_frames_per_pixel (fpu);
935 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
942 Editor::control_vertical_zoom_in_all ()
944 tav_zoom_smooth (false, true);
948 Editor::control_vertical_zoom_out_all ()
950 tav_zoom_smooth (true, true);
954 Editor::control_vertical_zoom_in_selected ()
956 tav_zoom_smooth (false, false);
960 Editor::control_vertical_zoom_out_selected ()
962 tav_zoom_smooth (true, false);
966 Editor::control_view (uint32_t view)
968 goto_visual_state (view);
972 Editor::control_unselect ()
974 selection->clear_tracks ();
978 Editor::control_select (uint32_t rid, Selection::Operation op)
980 /* handles the (static) signal from the ControlProtocol class that
981 * requests setting the selected track to a given RID
988 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
994 TimeAxisView* tav = axis_view_from_route (r);
999 selection->add (tav);
1001 case Selection::Toggle:
1002 selection->toggle (tav);
1004 case Selection::Extend:
1006 case Selection::Set:
1007 selection->set (tav);
1011 selection->clear_tracks ();
1016 Editor::control_step_tracks_up ()
1018 scroll_tracks_up_line ();
1022 Editor::control_step_tracks_down ()
1024 scroll_tracks_down_line ();
1028 Editor::control_scroll (float fraction)
1030 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1036 double step = fraction * current_page_frames();
1039 _control_scroll_target is an optional<T>
1041 it acts like a pointer to an framepos_t, with
1042 a operator conversion to boolean to check
1043 that it has a value could possibly use
1044 playhead_cursor->current_frame to store the
1045 value and a boolean in the class to know
1046 when it's out of date
1049 if (!_control_scroll_target) {
1050 _control_scroll_target = _session->transport_frame();
1051 _dragging_playhead = true;
1054 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1055 *_control_scroll_target = 0;
1056 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1057 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1059 *_control_scroll_target += (framepos_t) floor (step);
1062 /* move visuals, we'll catch up with it later */
1064 playhead_cursor->set_position (*_control_scroll_target);
1065 UpdateAllTransportClocks (*_control_scroll_target);
1067 if (*_control_scroll_target > (current_page_frames() / 2)) {
1068 /* try to center PH in window */
1069 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1075 Now we do a timeout to actually bring the session to the right place
1076 according to the playhead. This is to avoid reading disk buffers on every
1077 call to control_scroll, which is driven by ScrollTimeline and therefore
1078 probably by a control surface wheel which can generate lots of events.
1080 /* cancel the existing timeout */
1082 control_scroll_connection.disconnect ();
1084 /* add the next timeout */
1086 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1090 Editor::deferred_control_scroll (framepos_t /*target*/)
1092 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1093 // reset for next stream
1094 _control_scroll_target = boost::none;
1095 _dragging_playhead = false;
1100 Editor::access_action (std::string action_group, std::string action_item)
1106 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1109 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1117 Editor::on_realize ()
1119 Window::on_realize ();
1124 Editor::map_position_change (framepos_t frame)
1126 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1128 if (_session == 0) {
1132 if (_follow_playhead) {
1133 center_screen (frame);
1136 playhead_cursor->set_position (frame);
1140 Editor::center_screen (framepos_t frame)
1142 double const page = _visible_canvas_width * frames_per_pixel;
1144 /* if we're off the page, then scroll.
1147 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1148 center_screen_internal (frame, page);
1153 Editor::center_screen_internal (framepos_t frame, float page)
1158 frame -= (framepos_t) page;
1163 reset_x_origin (frame);
1168 Editor::update_title ()
1170 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1173 bool dirty = _session->dirty();
1175 string session_name;
1177 if (_session->snap_name() != _session->name()) {
1178 session_name = _session->snap_name();
1180 session_name = _session->name();
1184 session_name = "*" + session_name;
1187 WindowTitle title(session_name);
1188 title += Glib::get_application_name();
1189 set_title (title.get_string());
1191 /* ::session_going_away() will have taken care of it */
1196 Editor::set_session (Session *t)
1198 SessionHandlePtr::set_session (t);
1204 zoom_range_clock->set_session (_session);
1205 _playlist_selector->set_session (_session);
1206 nudge_clock->set_session (_session);
1207 _summary->set_session (_session);
1208 _group_tabs->set_session (_session);
1209 _route_groups->set_session (_session);
1210 _regions->set_session (_session);
1211 _snapshots->set_session (_session);
1212 _routes->set_session (_session);
1213 _locations->set_session (_session);
1215 if (rhythm_ferret) {
1216 rhythm_ferret->set_session (_session);
1219 if (analysis_window) {
1220 analysis_window->set_session (_session);
1224 sfbrowser->set_session (_session);
1227 compute_fixed_ruler_scale ();
1229 /* Make sure we have auto loop and auto punch ranges */
1231 Location* loc = _session->locations()->auto_loop_location();
1233 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1235 if (loc->start() == loc->end()) {
1236 loc->set_end (loc->start() + 1);
1239 _session->locations()->add (loc, false);
1240 _session->set_auto_loop_location (loc);
1243 loc->set_name (_("Loop"));
1246 loc = _session->locations()->auto_punch_location();
1249 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1251 if (loc->start() == loc->end()) {
1252 loc->set_end (loc->start() + 1);
1255 _session->locations()->add (loc, false);
1256 _session->set_auto_punch_location (loc);
1259 loc->set_name (_("Punch"));
1262 refresh_location_display ();
1264 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1265 the selected Marker; this needs the LocationMarker list to be available.
1267 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1268 set_state (*node, Stateful::loading_state_version);
1270 /* catch up with the playhead */
1272 _session->request_locate (playhead_cursor->current_frame ());
1273 _pending_initial_locate = true;
1277 /* These signals can all be emitted by a non-GUI thread. Therefore the
1278 handlers for them must not attempt to directly interact with the GUI,
1279 but use Gtkmm2ext::UI::instance()->call_slot();
1282 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1283 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1284 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1285 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1286 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1287 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1288 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1289 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1290 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1291 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1292 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1293 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1294 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1295 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1297 playhead_cursor->show ();
1299 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1300 Config->map_parameters (pc);
1301 _session->config.map_parameters (pc);
1303 restore_ruler_visibility ();
1304 //tempo_map_changed (PropertyChange (0));
1305 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1307 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1308 (static_cast<TimeAxisView*>(*i))->set_frames_per_pixel (frames_per_pixel);
1311 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1312 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1315 switch (_snap_type) {
1316 case SnapToRegionStart:
1317 case SnapToRegionEnd:
1318 case SnapToRegionSync:
1319 case SnapToRegionBoundary:
1320 build_region_boundary_cache ();
1327 /* register for undo history */
1328 _session->register_with_memento_command_factory(id(), this);
1330 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1332 start_updating_meters ();
1336 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1338 if (a->get_name() == "RegionMenu") {
1339 /* When the main menu's region menu is opened, we setup the actions so that they look right
1340 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1341 so we resensitize all region actions when the entered regionview or the region selection
1342 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1343 happens after the region context menu is opened. So we set a flag here, too.
1347 sensitize_the_right_region_actions ();
1348 _last_region_menu_was_main = true;
1353 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1355 using namespace Menu_Helpers;
1357 void (Editor::*emf)(FadeShape);
1358 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1361 images = &_xfade_in_images;
1362 emf = &Editor::set_fade_in_shape;
1364 images = &_xfade_out_images;
1365 emf = &Editor::set_fade_out_shape;
1370 _("Linear (for highly correlated material)"),
1371 *(*images)[FadeLinear],
1372 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1376 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1380 _("Constant power"),
1381 *(*images)[FadeConstantPower],
1382 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *(*images)[FadeSymmetric],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *(*images)[FadeSlow],
1401 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *(*images)[FadeFast],
1410 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1416 /** Pop up a context menu for when the user clicks on a start crossfade */
1418 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1420 using namespace Menu_Helpers;
1422 MenuList& items (xfade_in_context_menu.items());
1424 if (items.empty()) {
1425 fill_xfade_menu (items, true);
1428 xfade_in_context_menu.popup (button, time);
1431 /** Pop up a context menu for when the user clicks on an end crossfade */
1433 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1435 using namespace Menu_Helpers;
1437 MenuList& items (xfade_out_context_menu.items());
1439 if (items.empty()) {
1440 fill_xfade_menu (items, false);
1443 xfade_out_context_menu.popup (button, time);
1447 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1449 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1451 using namespace Menu_Helpers;
1452 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1455 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1459 MenuList& items (fade_context_menu.items());
1462 switch (item_type) {
1464 case FadeInHandleItem:
1465 if (arv->audio_region()->fade_in_active()) {
1466 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1468 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1471 items.push_back (SeparatorElem());
1473 if (Profile->get_sae()) {
1475 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1476 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1483 *_fade_in_images[FadeLinear],
1484 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 *_fade_in_images[FadeSlow],
1494 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *_fade_in_images[FadeFast],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *_fade_in_images[FadeSymmetric],
1512 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1517 _("Constant power"),
1518 *_fade_in_images[FadeConstantPower],
1519 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1522 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1528 case FadeOutHandleItem:
1529 if (arv->audio_region()->fade_out_active()) {
1530 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1532 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1535 items.push_back (SeparatorElem());
1537 if (Profile->get_sae()) {
1538 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1539 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1545 *_fade_out_images[FadeLinear],
1546 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1550 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1555 *_fade_out_images[FadeSlow],
1556 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1559 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1564 *_fade_out_images[FadeFast],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1568 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1573 *_fade_out_images[FadeSymmetric],
1574 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1579 _("Constant power"),
1580 *_fade_out_images[FadeConstantPower],
1581 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1584 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1590 fatal << _("programming error: ")
1591 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1596 fade_context_menu.popup (button, time);
1600 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1602 using namespace Menu_Helpers;
1603 Menu* (Editor::*build_menu_function)();
1606 switch (item_type) {
1608 case RegionViewName:
1609 case RegionViewNameHighlight:
1610 case LeftFrameHandle:
1611 case RightFrameHandle:
1612 if (with_selection) {
1613 build_menu_function = &Editor::build_track_selection_context_menu;
1615 build_menu_function = &Editor::build_track_region_context_menu;
1620 if (with_selection) {
1621 build_menu_function = &Editor::build_track_selection_context_menu;
1623 build_menu_function = &Editor::build_track_context_menu;
1628 if (clicked_routeview->track()) {
1629 build_menu_function = &Editor::build_track_context_menu;
1631 build_menu_function = &Editor::build_track_bus_context_menu;
1636 /* probably shouldn't happen but if it does, we don't care */
1640 menu = (this->*build_menu_function)();
1641 menu->set_name ("ArdourContextMenu");
1643 /* now handle specific situations */
1645 switch (item_type) {
1647 case RegionViewName:
1648 case RegionViewNameHighlight:
1649 case LeftFrameHandle:
1650 case RightFrameHandle:
1651 if (!with_selection) {
1652 if (region_edit_menu_split_item) {
1653 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1654 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1656 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1659 if (region_edit_menu_split_multichannel_item) {
1660 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1661 region_edit_menu_split_multichannel_item->set_sensitive (true);
1663 region_edit_menu_split_multichannel_item->set_sensitive (false);
1676 /* probably shouldn't happen but if it does, we don't care */
1680 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1682 /* Bounce to disk */
1684 using namespace Menu_Helpers;
1685 MenuList& edit_items = menu->items();
1687 edit_items.push_back (SeparatorElem());
1689 switch (clicked_routeview->audio_track()->freeze_state()) {
1690 case AudioTrack::NoFreeze:
1691 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1694 case AudioTrack::Frozen:
1695 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1698 case AudioTrack::UnFrozen:
1699 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1705 if (item_type == StreamItem && clicked_routeview) {
1706 clicked_routeview->build_underlay_menu(menu);
1709 /* When the region menu is opened, we setup the actions so that they look right
1712 sensitize_the_right_region_actions ();
1713 _last_region_menu_was_main = false;
1715 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1716 menu->popup (button, time);
1720 Editor::build_track_context_menu ()
1722 using namespace Menu_Helpers;
1724 MenuList& edit_items = track_context_menu.items();
1727 add_dstream_context_items (edit_items);
1728 return &track_context_menu;
1732 Editor::build_track_bus_context_menu ()
1734 using namespace Menu_Helpers;
1736 MenuList& edit_items = track_context_menu.items();
1739 add_bus_context_items (edit_items);
1740 return &track_context_menu;
1744 Editor::build_track_region_context_menu ()
1746 using namespace Menu_Helpers;
1747 MenuList& edit_items = track_region_context_menu.items();
1750 /* we've just cleared the track region context menu, so the menu that these
1751 two items were on will have disappeared; stop them dangling.
1753 region_edit_menu_split_item = 0;
1754 region_edit_menu_split_multichannel_item = 0;
1756 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1759 boost::shared_ptr<Track> tr;
1760 boost::shared_ptr<Playlist> pl;
1762 if ((tr = rtv->track())) {
1763 add_region_context_items (edit_items, tr);
1767 add_dstream_context_items (edit_items);
1769 return &track_region_context_menu;
1773 Editor::analyze_region_selection ()
1775 if (analysis_window == 0) {
1776 analysis_window = new AnalysisWindow();
1779 analysis_window->set_session(_session);
1781 analysis_window->show_all();
1784 analysis_window->set_regionmode();
1785 analysis_window->analyze();
1787 analysis_window->present();
1791 Editor::analyze_range_selection()
1793 if (analysis_window == 0) {
1794 analysis_window = new AnalysisWindow();
1797 analysis_window->set_session(_session);
1799 analysis_window->show_all();
1802 analysis_window->set_rangemode();
1803 analysis_window->analyze();
1805 analysis_window->present();
1809 Editor::build_track_selection_context_menu ()
1811 using namespace Menu_Helpers;
1812 MenuList& edit_items = track_selection_context_menu.items();
1813 edit_items.clear ();
1815 add_selection_context_items (edit_items);
1816 // edit_items.push_back (SeparatorElem());
1817 // add_dstream_context_items (edit_items);
1819 return &track_selection_context_menu;
1823 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1825 using namespace Menu_Helpers;
1827 /* OK, stick the region submenu at the top of the list, and then add
1831 RegionSelection rs = get_regions_from_selection_and_entered ();
1833 string::size_type pos = 0;
1834 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1836 /* we have to hack up the region name because "_" has a special
1837 meaning for menu titles.
1840 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1841 menu_item_name.replace (pos, 1, "__");
1845 if (_popup_region_menu_item == 0) {
1846 _popup_region_menu_item = new MenuItem (menu_item_name);
1847 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1848 _popup_region_menu_item->show ();
1850 _popup_region_menu_item->set_label (menu_item_name);
1853 const framepos_t position = get_preferred_edit_position (false, true);
1855 edit_items.push_back (*_popup_region_menu_item);
1856 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1857 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1859 edit_items.push_back (SeparatorElem());
1862 /** Add context menu items relevant to selection ranges.
1863 * @param edit_items List to add the items to.
1866 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1868 using namespace Menu_Helpers;
1870 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1871 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1876 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (
1880 _("Move Range Start to Previous Region Boundary"),
1881 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1885 edit_items.push_back (
1887 _("Move Range Start to Next Region Boundary"),
1888 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1892 edit_items.push_back (
1894 _("Move Range End to Previous Region Boundary"),
1895 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1899 edit_items.push_back (
1901 _("Move Range End to Next Region Boundary"),
1902 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1908 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1913 edit_items.push_back (SeparatorElem());
1914 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1915 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1917 edit_items.push_back (SeparatorElem());
1918 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1920 edit_items.push_back (SeparatorElem());
1921 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1922 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1923 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1925 edit_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1927 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1928 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1929 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1930 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1935 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1937 using namespace Menu_Helpers;
1941 Menu *play_menu = manage (new Menu);
1942 MenuList& play_items = play_menu->items();
1943 play_menu->set_name ("ArdourContextMenu");
1945 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1946 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1947 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1948 play_items.push_back (SeparatorElem());
1949 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1951 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1955 Menu *select_menu = manage (new Menu);
1956 MenuList& select_items = select_menu->items();
1957 select_menu->set_name ("ArdourContextMenu");
1959 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1960 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1961 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1962 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1963 select_items.push_back (SeparatorElem());
1964 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1965 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1966 select_items.push_back (SeparatorElem());
1967 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1968 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1969 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1970 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1971 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1972 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1973 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1975 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1979 Menu *cutnpaste_menu = manage (new Menu);
1980 MenuList& cutnpaste_items = cutnpaste_menu->items();
1981 cutnpaste_menu->set_name ("ArdourContextMenu");
1983 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1984 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1985 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1987 cutnpaste_items.push_back (SeparatorElem());
1989 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1990 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1992 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1994 /* Adding new material */
1996 edit_items.push_back (SeparatorElem());
1997 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1998 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2002 Menu *nudge_menu = manage (new Menu());
2003 MenuList& nudge_items = nudge_menu->items();
2004 nudge_menu->set_name ("ArdourContextMenu");
2006 edit_items.push_back (SeparatorElem());
2007 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2008 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2009 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2010 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2012 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2016 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2018 using namespace Menu_Helpers;
2022 Menu *play_menu = manage (new Menu);
2023 MenuList& play_items = play_menu->items();
2024 play_menu->set_name ("ArdourContextMenu");
2026 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2027 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2028 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2032 Menu *select_menu = manage (new Menu);
2033 MenuList& select_items = select_menu->items();
2034 select_menu->set_name ("ArdourContextMenu");
2036 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2037 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2038 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2039 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2040 select_items.push_back (SeparatorElem());
2041 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2042 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2043 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2044 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2046 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2050 Menu *cutnpaste_menu = manage (new Menu);
2051 MenuList& cutnpaste_items = cutnpaste_menu->items();
2052 cutnpaste_menu->set_name ("ArdourContextMenu");
2054 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2055 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2056 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2058 Menu *nudge_menu = manage (new Menu());
2059 MenuList& nudge_items = nudge_menu->items();
2060 nudge_menu->set_name ("ArdourContextMenu");
2062 edit_items.push_back (SeparatorElem());
2063 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2064 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2065 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2066 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2068 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2072 Editor::snap_type() const
2078 Editor::snap_mode() const
2084 Editor::set_snap_to (SnapType st)
2086 unsigned int snap_ind = (unsigned int)st;
2090 if (snap_ind > snap_type_strings.size() - 1) {
2092 _snap_type = (SnapType)snap_ind;
2095 string str = snap_type_strings[snap_ind];
2097 if (str != snap_type_selector.get_active_text()) {
2098 snap_type_selector.set_active_text (str);
2103 switch (_snap_type) {
2104 case SnapToBeatDiv128:
2105 case SnapToBeatDiv64:
2106 case SnapToBeatDiv32:
2107 case SnapToBeatDiv28:
2108 case SnapToBeatDiv24:
2109 case SnapToBeatDiv20:
2110 case SnapToBeatDiv16:
2111 case SnapToBeatDiv14:
2112 case SnapToBeatDiv12:
2113 case SnapToBeatDiv10:
2114 case SnapToBeatDiv8:
2115 case SnapToBeatDiv7:
2116 case SnapToBeatDiv6:
2117 case SnapToBeatDiv5:
2118 case SnapToBeatDiv4:
2119 case SnapToBeatDiv3:
2120 case SnapToBeatDiv2: {
2121 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2122 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2124 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2125 current_bbt_points_begin, current_bbt_points_end);
2126 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2127 current_bbt_points_begin, current_bbt_points_end);
2128 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2132 case SnapToRegionStart:
2133 case SnapToRegionEnd:
2134 case SnapToRegionSync:
2135 case SnapToRegionBoundary:
2136 build_region_boundary_cache ();
2144 SnapChanged (); /* EMIT SIGNAL */
2148 Editor::set_snap_mode (SnapMode mode)
2150 string str = snap_mode_strings[(int)mode];
2152 if (_internal_editing) {
2153 internal_snap_mode = mode;
2155 pre_internal_snap_mode = mode;
2160 if (str != snap_mode_selector.get_active_text ()) {
2161 snap_mode_selector.set_active_text (str);
2167 Editor::set_edit_point_preference (EditPoint ep, bool force)
2169 bool changed = (_edit_point != ep);
2172 string str = edit_point_strings[(int)ep];
2174 if (str != edit_point_selector.get_active_text ()) {
2175 edit_point_selector.set_active_text (str);
2178 set_canvas_cursor ();
2180 if (!force && !changed) {
2184 const char* action=NULL;
2186 switch (_edit_point) {
2187 case EditAtPlayhead:
2188 action = "edit-at-playhead";
2190 case EditAtSelectedMarker:
2191 action = "edit-at-marker";
2194 action = "edit-at-mouse";
2198 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2200 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2204 bool in_track_canvas;
2206 if (!mouse_frame (foo, in_track_canvas)) {
2207 in_track_canvas = false;
2210 reset_canvas_action_sensitivity (in_track_canvas);
2216 Editor::set_state (const XMLNode& node, int /*version*/)
2218 const XMLProperty* prop;
2225 g.base_width = default_width;
2226 g.base_height = default_height;
2230 if ((geometry = find_named_node (node, "geometry")) != 0) {
2234 if ((prop = geometry->property("x_size")) == 0) {
2235 prop = geometry->property ("x-size");
2238 g.base_width = atoi(prop->value());
2240 if ((prop = geometry->property("y_size")) == 0) {
2241 prop = geometry->property ("y-size");
2244 g.base_height = atoi(prop->value());
2247 if ((prop = geometry->property ("x_pos")) == 0) {
2248 prop = geometry->property ("x-pos");
2251 x = atoi (prop->value());
2254 if ((prop = geometry->property ("y_pos")) == 0) {
2255 prop = geometry->property ("y-pos");
2258 y = atoi (prop->value());
2262 set_default_size (g.base_width, g.base_height);
2265 if (_session && (prop = node.property ("playhead"))) {
2267 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2268 playhead_cursor->set_position (pos);
2270 playhead_cursor->set_position (0);
2273 if ((prop = node.property ("mixer-width"))) {
2274 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2277 if ((prop = node.property ("zoom-focus"))) {
2278 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2281 if ((prop = node.property ("zoom"))) {
2282 reset_zoom (PBD::atof (prop->value()));
2284 reset_zoom (frames_per_pixel);
2287 if ((prop = node.property ("snap-to"))) {
2288 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2291 if ((prop = node.property ("snap-mode"))) {
2292 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2295 if ((prop = node.property ("internal-snap-to"))) {
2296 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2299 if ((prop = node.property ("internal-snap-mode"))) {
2300 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2303 if ((prop = node.property ("pre-internal-snap-to"))) {
2304 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2308 if ((prop = node.property ("pre-internal-snap-mode"))) {
2309 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2312 if ((prop = node.property ("mouse-mode"))) {
2313 MouseMode m = str2mousemode(prop->value());
2314 set_mouse_mode (m, true);
2316 set_mouse_mode (MouseObject, true);
2319 if ((prop = node.property ("left-frame")) != 0) {
2321 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2325 reset_x_origin (pos);
2329 if ((prop = node.property ("y-origin")) != 0) {
2330 reset_y_origin (atof (prop->value ()));
2333 if ((prop = node.property ("internal-edit"))) {
2334 bool yn = string_is_affirmative (prop->value());
2335 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2343 if ((prop = node.property ("join-object-range"))) {
2344 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2345 bool yn = string_is_affirmative (prop->value());
2347 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2348 tact->set_active (!yn);
2349 tact->set_active (yn);
2351 set_mouse_mode(mouse_mode, true);
2354 if ((prop = node.property ("edit-point"))) {
2355 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2358 if ((prop = node.property ("show-measures"))) {
2359 bool yn = string_is_affirmative (prop->value());
2360 _show_measures = yn;
2361 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2363 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2364 /* do it twice to force the change */
2365 tact->set_active (!yn);
2366 tact->set_active (yn);
2370 if ((prop = node.property ("follow-playhead"))) {
2371 bool yn = string_is_affirmative (prop->value());
2372 set_follow_playhead (yn);
2373 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2375 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2376 if (tact->get_active() != yn) {
2377 tact->set_active (yn);
2382 if ((prop = node.property ("stationary-playhead"))) {
2383 bool yn = string_is_affirmative (prop->value());
2384 set_stationary_playhead (yn);
2385 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2387 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2388 if (tact->get_active() != yn) {
2389 tact->set_active (yn);
2394 if ((prop = node.property ("region-list-sort-type"))) {
2395 RegionListSortType st;
2396 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2399 if ((prop = node.property ("show-editor-mixer"))) {
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
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 ("show-editor-list"))) {
2415 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2418 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2419 bool yn = string_is_affirmative (prop->value());
2421 /* do it twice to force the change */
2423 tact->set_active (!yn);
2424 tact->set_active (yn);
2427 if ((prop = node.property (X_("editor-list-page")))) {
2428 _the_notebook.set_current_page (atoi (prop->value ()));
2431 if ((prop = node.property (X_("show-marker-lines")))) {
2432 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2434 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2435 bool yn = string_is_affirmative (prop->value ());
2437 tact->set_active (!yn);
2438 tact->set_active (yn);
2441 XMLNodeList children = node.children ();
2442 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2443 selection->set_state (**i, Stateful::current_state_version);
2444 _regions->set_state (**i);
2447 if ((prop = node.property ("maximised"))) {
2448 bool yn = string_is_affirmative (prop->value());
2450 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2454 if ((prop = node.property ("nudge-clock-value"))) {
2456 sscanf (prop->value().c_str(), "%" PRId64, &f);
2457 nudge_clock->set (f);
2459 nudge_clock->set_mode (AudioClock::Timecode);
2460 nudge_clock->set (_session->frame_rate() * 5, true);
2467 Editor::get_state ()
2469 XMLNode* node = new XMLNode ("Editor");
2472 id().print (buf, sizeof (buf));
2473 node->add_property ("id", buf);
2475 if (is_realized()) {
2476 Glib::RefPtr<Gdk::Window> win = get_window();
2478 int x, y, width, height;
2479 win->get_root_origin(x, y);
2480 win->get_size(width, height);
2482 XMLNode* geometry = new XMLNode ("geometry");
2484 snprintf(buf, sizeof(buf), "%d", width);
2485 geometry->add_property("x-size", string(buf));
2486 snprintf(buf, sizeof(buf), "%d", height);
2487 geometry->add_property("y-size", string(buf));
2488 snprintf(buf, sizeof(buf), "%d", x);
2489 geometry->add_property("x-pos", string(buf));
2490 snprintf(buf, sizeof(buf), "%d", y);
2491 geometry->add_property("y-pos", string(buf));
2492 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2493 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2494 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2495 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2496 geometry->add_property("edit-vertical-pane-pos", string(buf));
2498 node->add_child_nocopy (*geometry);
2501 maybe_add_mixer_strip_width (*node);
2503 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2504 snprintf (buf, sizeof(buf), "%f", frames_per_pixel);
2505 node->add_property ("zoom", buf);
2506 node->add_property ("snap-to", enum_2_string (_snap_type));
2507 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2508 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2509 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2510 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2511 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2512 node->add_property ("edit-point", enum_2_string (_edit_point));
2514 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2515 node->add_property ("playhead", buf);
2516 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2517 node->add_property ("left-frame", buf);
2518 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2519 node->add_property ("y-origin", buf);
2521 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2522 node->add_property ("maximised", _maximised ? "yes" : "no");
2523 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2524 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2525 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2526 node->add_property ("mouse-mode", enum2str(mouse_mode));
2527 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2528 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2530 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2532 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2533 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2536 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2538 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2539 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2542 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2543 node->add_property (X_("editor-list-page"), buf);
2545 if (button_bindings) {
2546 XMLNode* bb = new XMLNode (X_("Buttons"));
2547 button_bindings->save (*bb);
2548 node->add_child_nocopy (*bb);
2551 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2553 node->add_child_nocopy (selection->get_state ());
2554 node->add_child_nocopy (_regions->get_state ());
2556 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2557 node->add_property ("nudge-clock-value", buf);
2564 /** @param y y offset from the top of all trackviews.
2565 * @return pair: TimeAxisView that y is over, layer index.
2566 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2567 * in stacked or expanded region display mode, otherwise 0.
2569 std::pair<TimeAxisView *, double>
2570 Editor::trackview_by_y_position (double y)
2572 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2574 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2580 return std::make_pair ( (TimeAxisView *) 0, 0);
2583 /** Snap a position to the grid, if appropriate, taking into account current
2584 * grid settings and also the state of any snap modifier keys that may be pressed.
2585 * @param start Position to snap.
2586 * @param event Event to get current key modifier information from, or 0.
2589 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2591 if (!_session || !event) {
2595 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2596 if (_snap_mode == SnapOff) {
2597 snap_to_internal (start, direction, for_mark);
2600 if (_snap_mode != SnapOff) {
2601 snap_to_internal (start, direction, for_mark);
2607 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2609 if (!_session || _snap_mode == SnapOff) {
2613 snap_to_internal (start, direction, for_mark);
2617 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2619 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2620 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2622 switch (_snap_type) {
2623 case SnapToTimecodeFrame:
2624 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2625 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2627 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2631 case SnapToTimecodeSeconds:
2632 if (_session->config.get_timecode_offset_negative()) {
2633 start += _session->config.get_timecode_offset ();
2635 start -= _session->config.get_timecode_offset ();
2637 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2638 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2640 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start -= _session->config.get_timecode_offset ();
2646 start += _session->config.get_timecode_offset ();
2650 case SnapToTimecodeMinutes:
2651 if (_session->config.get_timecode_offset_negative()) {
2652 start += _session->config.get_timecode_offset ();
2654 start -= _session->config.get_timecode_offset ();
2656 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2657 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2659 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2661 if (_session->config.get_timecode_offset_negative()) {
2662 start -= _session->config.get_timecode_offset ();
2664 start += _session->config.get_timecode_offset ();
2668 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2674 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2676 const framepos_t one_second = _session->frame_rate();
2677 const framepos_t one_minute = _session->frame_rate() * 60;
2678 framepos_t presnap = start;
2682 switch (_snap_type) {
2683 case SnapToTimecodeFrame:
2684 case SnapToTimecodeSeconds:
2685 case SnapToTimecodeMinutes:
2686 return timecode_snap_to_internal (start, direction, for_mark);
2689 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2690 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2692 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2697 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2698 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2700 start = (framepos_t) floor ((double) start / one_second) * one_second;
2705 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2706 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2708 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2713 start = _session->tempo_map().round_to_bar (start, direction);
2717 start = _session->tempo_map().round_to_beat (start, direction);
2720 case SnapToBeatDiv128:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2723 case SnapToBeatDiv64:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2726 case SnapToBeatDiv32:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2729 case SnapToBeatDiv28:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2732 case SnapToBeatDiv24:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2735 case SnapToBeatDiv20:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2738 case SnapToBeatDiv16:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2741 case SnapToBeatDiv14:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2744 case SnapToBeatDiv12:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2747 case SnapToBeatDiv10:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2750 case SnapToBeatDiv8:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2753 case SnapToBeatDiv7:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2756 case SnapToBeatDiv6:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2759 case SnapToBeatDiv5:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2762 case SnapToBeatDiv4:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2765 case SnapToBeatDiv3:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2768 case SnapToBeatDiv2:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2777 _session->locations()->marks_either_side (start, before, after);
2779 if (before == max_framepos && after == max_framepos) {
2780 /* No marks to snap to, so just don't snap */
2782 } else if (before == max_framepos) {
2784 } else if (after == max_framepos) {
2786 } else if (before != max_framepos && after != max_framepos) {
2787 /* have before and after */
2788 if ((start - before) < (after - start)) {
2797 case SnapToRegionStart:
2798 case SnapToRegionEnd:
2799 case SnapToRegionSync:
2800 case SnapToRegionBoundary:
2801 if (!region_boundary_cache.empty()) {
2803 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2804 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2806 if (direction > 0) {
2807 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2809 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2812 if (next != region_boundary_cache.begin ()) {
2817 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2818 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2820 if (start > (p + n) / 2) {
2829 switch (_snap_mode) {
2835 if (presnap > start) {
2836 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2840 } else if (presnap < start) {
2841 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2847 /* handled at entry */
2855 Editor::setup_toolbar ()
2857 HBox* mode_box = manage(new HBox);
2858 mode_box->set_border_width (2);
2859 mode_box->set_spacing(4);
2861 HBox* mouse_mode_box = manage (new HBox);
2862 HBox* mouse_mode_hbox = manage (new HBox);
2863 VBox* mouse_mode_vbox = manage (new VBox);
2864 Alignment* mouse_mode_align = manage (new Alignment);
2866 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2867 // mouse_mode_size_group->add_widget (smart_mode_button);
2868 mouse_mode_size_group->add_widget (mouse_move_button);
2869 mouse_mode_size_group->add_widget (mouse_select_button);
2870 mouse_mode_size_group->add_widget (mouse_zoom_button);
2871 mouse_mode_size_group->add_widget (mouse_gain_button);
2872 mouse_mode_size_group->add_widget (mouse_timefx_button);
2873 mouse_mode_size_group->add_widget (mouse_audition_button);
2874 mouse_mode_size_group->add_widget (mouse_draw_button);
2875 mouse_mode_size_group->add_widget (internal_edit_button);
2877 /* make them just a bit bigger */
2878 mouse_move_button.set_size_request (-1, 30);
2880 mouse_mode_hbox->set_spacing (2);
2882 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2883 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2884 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2885 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2886 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2890 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2892 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2894 mouse_mode_align->add (*mouse_mode_vbox);
2895 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2897 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2899 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2900 if (!Profile->get_sae()) {
2901 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2903 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2905 edit_mode_selector.set_name ("EditModeSelector");
2906 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2907 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2909 mode_box->pack_start (edit_mode_selector, false, false);
2910 mode_box->pack_start (*mouse_mode_box, false, false);
2912 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2913 _mouse_mode_tearoff->set_name ("MouseModeBase");
2914 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2916 if (Profile->get_sae()) {
2917 _mouse_mode_tearoff->set_can_be_torn_off (false);
2920 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2921 &_mouse_mode_tearoff->tearoff_window()));
2922 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2923 &_mouse_mode_tearoff->tearoff_window(), 1));
2924 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window()));
2926 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window(), 1));
2931 _zoom_box.set_spacing (2);
2932 _zoom_box.set_border_width (2);
2936 zoom_in_button.set_name ("zoom button");
2937 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2938 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2939 zoom_in_button.set_image(::get_icon ("zoom_in"));
2940 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2941 zoom_in_button.set_related_action (act);
2943 zoom_out_button.set_name ("zoom button");
2944 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2945 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2946 zoom_out_button.set_image(::get_icon ("zoom_out"));
2947 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2948 zoom_out_button.set_related_action (act);
2950 zoom_out_full_button.set_name ("zoom button");
2951 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2952 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2953 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2954 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2955 zoom_out_full_button.set_related_action (act);
2957 zoom_focus_selector.set_name ("ZoomFocusSelector");
2958 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2959 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2961 _zoom_box.pack_start (zoom_out_button, false, false);
2962 _zoom_box.pack_start (zoom_in_button, false, false);
2963 _zoom_box.pack_start (zoom_out_full_button, false, false);
2965 _zoom_box.pack_start (zoom_focus_selector, false, false);
2967 /* Track zoom buttons */
2968 tav_expand_button.set_name ("zoom button");
2969 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2970 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2971 tav_expand_button.set_size_request (-1, 20);
2972 tav_expand_button.set_image(::get_icon ("tav_exp"));
2973 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2974 tav_expand_button.set_related_action (act);
2976 tav_shrink_button.set_name ("zoom button");
2977 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2978 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2979 tav_shrink_button.set_size_request (-1, 20);
2980 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2981 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2982 tav_shrink_button.set_related_action (act);
2984 _zoom_box.pack_start (tav_shrink_button);
2985 _zoom_box.pack_start (tav_expand_button);
2987 _zoom_tearoff = manage (new TearOff (_zoom_box));
2989 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_zoom_tearoff->tearoff_window()));
2991 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_zoom_tearoff->tearoff_window(), 0));
2993 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2994 &_zoom_tearoff->tearoff_window()));
2995 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2996 &_zoom_tearoff->tearoff_window(), 0));
2998 snap_box.set_spacing (2);
2999 snap_box.set_border_width (2);
3001 snap_type_selector.set_name ("SnapTypeSelector");
3002 set_popdown_strings (snap_type_selector, snap_type_strings);
3003 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3005 snap_mode_selector.set_name ("SnapModeSelector");
3006 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3007 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3009 edit_point_selector.set_name ("EditPointSelector");
3010 set_popdown_strings (edit_point_selector, edit_point_strings);
3011 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3013 snap_box.pack_start (snap_mode_selector, false, false);
3014 snap_box.pack_start (snap_type_selector, false, false);
3015 snap_box.pack_start (edit_point_selector, false, false);
3019 HBox *nudge_box = manage (new HBox);
3020 nudge_box->set_spacing (2);
3021 nudge_box->set_border_width (2);
3023 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3024 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3026 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3027 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3029 nudge_box->pack_start (nudge_backward_button, false, false);
3030 nudge_box->pack_start (nudge_forward_button, false, false);
3031 nudge_box->pack_start (*nudge_clock, false, false);
3034 /* Pack everything in... */
3036 HBox* hbox = manage (new HBox);
3037 hbox->set_spacing(10);
3039 _tools_tearoff = manage (new TearOff (*hbox));
3040 _tools_tearoff->set_name ("MouseModeBase");
3041 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3043 if (Profile->get_sae()) {
3044 _tools_tearoff->set_can_be_torn_off (false);
3047 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3048 &_tools_tearoff->tearoff_window()));
3049 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3050 &_tools_tearoff->tearoff_window(), 0));
3051 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3052 &_tools_tearoff->tearoff_window()));
3053 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3054 &_tools_tearoff->tearoff_window(), 0));
3056 toolbar_hbox.set_spacing (10);
3057 toolbar_hbox.set_border_width (1);
3059 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3060 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3061 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3063 hbox->pack_start (snap_box, false, false);
3064 if (!Profile->get_small_screen()) {
3065 hbox->pack_start (*nudge_box, false, false);
3067 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3069 hbox->pack_start (panic_box, false, false);
3073 toolbar_base.set_name ("ToolBarBase");
3074 toolbar_base.add (toolbar_hbox);
3076 _toolbar_viewport.add (toolbar_base);
3077 /* stick to the required height but allow width to vary if there's not enough room */
3078 _toolbar_viewport.set_size_request (1, -1);
3080 toolbar_frame.set_shadow_type (SHADOW_OUT);
3081 toolbar_frame.set_name ("BaseFrame");
3082 toolbar_frame.add (_toolbar_viewport);
3086 Editor::setup_tooltips ()
3088 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3089 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3090 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3091 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3092 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3093 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3094 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3095 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3096 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3097 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3098 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3099 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3100 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3101 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3102 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3103 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3104 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3105 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3106 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3107 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3108 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3109 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3110 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3114 Editor::convert_drop_to_paths (
3115 vector<string>& paths,
3116 const RefPtr<Gdk::DragContext>& /*context*/,
3119 const SelectionData& data,
3123 if (_session == 0) {
3127 vector<string> uris = data.get_uris();
3131 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3132 are actually URI lists. So do it by hand.
3135 if (data.get_target() != "text/plain") {
3139 /* Parse the "uri-list" format that Nautilus provides,
3140 where each pathname is delimited by \r\n.
3142 THERE MAY BE NO NULL TERMINATING CHAR!!!
3145 string txt = data.get_text();
3149 p = (const char *) malloc (txt.length() + 1);
3150 txt.copy (const_cast<char *> (p), txt.length(), 0);
3151 const_cast<char*>(p)[txt.length()] = '\0';
3157 while (g_ascii_isspace (*p))
3161 while (*q && (*q != '\n') && (*q != '\r')) {
3168 while (q > p && g_ascii_isspace (*q))
3173 uris.push_back (string (p, q - p + 1));
3177 p = strchr (p, '\n');
3189 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3191 if ((*i).substr (0,7) == "file://") {
3193 string const p = PBD::url_decode (*i);
3195 // scan forward past three slashes
3197 string::size_type slashcnt = 0;
3198 string::size_type n = 0;
3199 string::const_iterator x = p.begin();
3201 while (slashcnt < 3 && x != p.end()) {
3204 } else if (slashcnt == 3) {
3211 if (slashcnt != 3 || x == p.end()) {
3212 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3216 paths.push_back (p.substr (n - 1));
3224 Editor::new_tempo_section ()
3230 Editor::map_transport_state ()
3232 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3234 if (_session && _session->transport_stopped()) {
3235 have_pending_keyboard_selection = false;
3238 update_loop_range_view (true);
3244 Editor::begin_reversible_command (string name)
3247 _session->begin_reversible_command (name);
3252 Editor::begin_reversible_command (GQuark q)
3255 _session->begin_reversible_command (q);
3260 Editor::commit_reversible_command ()
3263 _session->commit_reversible_command ();
3268 Editor::history_changed ()
3272 if (undo_action && _session) {
3273 if (_session->undo_depth() == 0) {
3274 label = S_("Command|Undo");
3276 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3278 undo_action->property_label() = label;
3281 if (redo_action && _session) {
3282 if (_session->redo_depth() == 0) {
3285 label = string_compose(_("Redo (%1)"), _session->next_redo());
3287 redo_action->property_label() = label;
3292 Editor::duplicate_range (bool with_dialog)
3296 RegionSelection rs = get_regions_from_selection_and_entered ();
3298 if ( selection->time.length() == 0 && rs.empty()) {
3304 ArdourDialog win (_("Duplicate"));
3305 Label label (_("Number of duplications:"));
3306 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3307 SpinButton spinner (adjustment, 0.0, 1);
3310 win.get_vbox()->set_spacing (12);
3311 win.get_vbox()->pack_start (hbox);
3312 hbox.set_border_width (6);
3313 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3315 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3316 place, visually. so do this by hand.
3319 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3320 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3321 spinner.grab_focus();
3327 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3328 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3329 win.set_default_response (RESPONSE_ACCEPT);
3331 win.set_position (WIN_POS_MOUSE);
3333 spinner.grab_focus ();
3335 switch (win.run ()) {
3336 case RESPONSE_ACCEPT:
3342 times = adjustment.get_value();
3345 if ((current_mouse_mode() == Editing::MouseRange)) {
3346 if (selection->time.length()) {
3347 duplicate_selection (times);
3349 } else if (get_smart_mode()) {
3350 if (selection->time.length()) {
3351 duplicate_selection (times);
3353 duplicate_some_regions (rs, times);
3355 duplicate_some_regions (rs, times);
3360 Editor::set_edit_mode (EditMode m)
3362 Config->set_edit_mode (m);
3366 Editor::cycle_edit_mode ()
3368 switch (Config->get_edit_mode()) {
3370 if (Profile->get_sae()) {
3371 Config->set_edit_mode (Lock);
3373 Config->set_edit_mode (Splice);
3377 Config->set_edit_mode (Lock);
3380 Config->set_edit_mode (Slide);
3386 Editor::edit_mode_selection_done ()
3388 string s = edit_mode_selector.get_active_text ();
3391 Config->set_edit_mode (string_to_edit_mode (s));
3396 Editor::snap_type_selection_done ()
3398 string choice = snap_type_selector.get_active_text();
3399 SnapType snaptype = SnapToBeat;
3401 if (choice == _("Beats/2")) {
3402 snaptype = SnapToBeatDiv2;
3403 } else if (choice == _("Beats/3")) {
3404 snaptype = SnapToBeatDiv3;
3405 } else if (choice == _("Beats/4")) {
3406 snaptype = SnapToBeatDiv4;
3407 } else if (choice == _("Beats/5")) {
3408 snaptype = SnapToBeatDiv5;
3409 } else if (choice == _("Beats/6")) {
3410 snaptype = SnapToBeatDiv6;
3411 } else if (choice == _("Beats/7")) {
3412 snaptype = SnapToBeatDiv7;
3413 } else if (choice == _("Beats/8")) {
3414 snaptype = SnapToBeatDiv8;
3415 } else if (choice == _("Beats/10")) {
3416 snaptype = SnapToBeatDiv10;
3417 } else if (choice == _("Beats/12")) {
3418 snaptype = SnapToBeatDiv12;
3419 } else if (choice == _("Beats/14")) {
3420 snaptype = SnapToBeatDiv14;
3421 } else if (choice == _("Beats/16")) {
3422 snaptype = SnapToBeatDiv16;
3423 } else if (choice == _("Beats/20")) {
3424 snaptype = SnapToBeatDiv20;
3425 } else if (choice == _("Beats/24")) {
3426 snaptype = SnapToBeatDiv24;
3427 } else if (choice == _("Beats/28")) {
3428 snaptype = SnapToBeatDiv28;
3429 } else if (choice == _("Beats/32")) {
3430 snaptype = SnapToBeatDiv32;
3431 } else if (choice == _("Beats/64")) {
3432 snaptype = SnapToBeatDiv64;
3433 } else if (choice == _("Beats/128")) {
3434 snaptype = SnapToBeatDiv128;
3435 } else if (choice == _("Beats")) {
3436 snaptype = SnapToBeat;
3437 } else if (choice == _("Bars")) {
3438 snaptype = SnapToBar;
3439 } else if (choice == _("Marks")) {
3440 snaptype = SnapToMark;
3441 } else if (choice == _("Region starts")) {
3442 snaptype = SnapToRegionStart;
3443 } else if (choice == _("Region ends")) {
3444 snaptype = SnapToRegionEnd;
3445 } else if (choice == _("Region bounds")) {
3446 snaptype = SnapToRegionBoundary;
3447 } else if (choice == _("Region syncs")) {
3448 snaptype = SnapToRegionSync;
3449 } else if (choice == _("CD Frames")) {
3450 snaptype = SnapToCDFrame;
3451 } else if (choice == _("Timecode Frames")) {
3452 snaptype = SnapToTimecodeFrame;
3453 } else if (choice == _("Timecode Seconds")) {
3454 snaptype = SnapToTimecodeSeconds;
3455 } else if (choice == _("Timecode Minutes")) {
3456 snaptype = SnapToTimecodeMinutes;
3457 } else if (choice == _("Seconds")) {
3458 snaptype = SnapToSeconds;
3459 } else if (choice == _("Minutes")) {
3460 snaptype = SnapToMinutes;
3463 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3465 ract->set_active ();
3470 Editor::snap_mode_selection_done ()
3472 string choice = snap_mode_selector.get_active_text();
3473 SnapMode mode = SnapNormal;
3475 if (choice == _("No Grid")) {
3477 } else if (choice == _("Grid")) {
3479 } else if (choice == _("Magnetic")) {
3480 mode = SnapMagnetic;
3483 RefPtr<RadioAction> ract = snap_mode_action (mode);
3486 ract->set_active (true);
3491 Editor::cycle_edit_point (bool with_marker)
3493 switch (_edit_point) {
3495 set_edit_point_preference (EditAtPlayhead);
3497 case EditAtPlayhead:
3499 set_edit_point_preference (EditAtSelectedMarker);
3501 set_edit_point_preference (EditAtMouse);
3504 case EditAtSelectedMarker:
3505 set_edit_point_preference (EditAtMouse);
3511 Editor::edit_point_selection_done ()
3513 string choice = edit_point_selector.get_active_text();
3514 EditPoint ep = EditAtSelectedMarker;
3516 if (choice == _("Marker")) {
3517 set_edit_point_preference (EditAtSelectedMarker);
3518 } else if (choice == _("Playhead")) {
3519 set_edit_point_preference (EditAtPlayhead);
3521 set_edit_point_preference (EditAtMouse);
3524 RefPtr<RadioAction> ract = edit_point_action (ep);
3527 ract->set_active (true);
3532 Editor::zoom_focus_selection_done ()
3534 string choice = zoom_focus_selector.get_active_text();
3535 ZoomFocus focus_type = ZoomFocusLeft;
3537 if (choice == _("Left")) {
3538 focus_type = ZoomFocusLeft;
3539 } else if (choice == _("Right")) {
3540 focus_type = ZoomFocusRight;
3541 } else if (choice == _("Center")) {
3542 focus_type = ZoomFocusCenter;
3543 } else if (choice == _("Playhead")) {
3544 focus_type = ZoomFocusPlayhead;
3545 } else if (choice == _("Mouse")) {
3546 focus_type = ZoomFocusMouse;
3547 } else if (choice == _("Edit point")) {
3548 focus_type = ZoomFocusEdit;
3551 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3554 ract->set_active ();
3559 Editor::edit_controls_button_release (GdkEventButton* ev)
3561 if (Keyboard::is_context_menu_event (ev)) {
3562 ARDOUR_UI::instance()->add_route (this);
3563 } else if (ev->button == 1) {
3564 selection->clear_tracks ();
3571 Editor::mouse_select_button_release (GdkEventButton* ev)
3573 /* this handles just right-clicks */
3575 if (ev->button != 3) {
3583 Editor::set_zoom_focus (ZoomFocus f)
3585 string str = zoom_focus_strings[(int)f];
3587 if (str != zoom_focus_selector.get_active_text()) {
3588 zoom_focus_selector.set_active_text (str);
3591 if (zoom_focus != f) {
3598 Editor::cycle_zoom_focus ()
3600 switch (zoom_focus) {
3602 set_zoom_focus (ZoomFocusRight);
3604 case ZoomFocusRight:
3605 set_zoom_focus (ZoomFocusCenter);
3607 case ZoomFocusCenter:
3608 set_zoom_focus (ZoomFocusPlayhead);
3610 case ZoomFocusPlayhead:
3611 set_zoom_focus (ZoomFocusMouse);
3613 case ZoomFocusMouse:
3614 set_zoom_focus (ZoomFocusEdit);
3617 set_zoom_focus (ZoomFocusLeft);
3623 Editor::ensure_float (Window& win)
3625 win.set_transient_for (*this);
3629 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3631 /* recover or initialize pane positions. do this here rather than earlier because
3632 we don't want the positions to change the child allocations, which they seem to do.
3638 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3647 XMLNode* geometry = find_named_node (*node, "geometry");
3649 if (which == static_cast<Paned*> (&edit_pane)) {
3651 if (done & Horizontal) {
3655 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3656 _notebook_shrunk = string_is_affirmative (prop->value ());
3659 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3660 /* initial allocation is 90% to canvas, 10% to notebook */
3661 pos = (int) floor (alloc.get_width() * 0.90f);
3662 snprintf (buf, sizeof(buf), "%d", pos);
3664 pos = atoi (prop->value());
3667 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3668 edit_pane.set_position (pos);
3671 done = (Pane) (done | Horizontal);
3673 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3675 if (done & Vertical) {
3679 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3680 /* initial allocation is 90% to canvas, 10% to summary */
3681 pos = (int) floor (alloc.get_height() * 0.90f);
3682 snprintf (buf, sizeof(buf), "%d", pos);
3685 pos = atoi (prop->value());
3688 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3689 editor_summary_pane.set_position (pos);
3692 done = (Pane) (done | Vertical);
3697 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3699 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3700 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3701 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3702 top_hbox.remove (toolbar_frame);
3707 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3709 if (toolbar_frame.get_parent() == 0) {
3710 top_hbox.pack_end (toolbar_frame);
3715 Editor::set_show_measures (bool yn)
3717 if (_show_measures != yn) {
3720 if ((_show_measures = yn) == true) {
3722 tempo_lines->show();
3724 (void) redraw_measures ();
3731 Editor::toggle_follow_playhead ()
3733 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3735 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3736 set_follow_playhead (tact->get_active());
3740 /** @param yn true to follow playhead, otherwise false.
3741 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3744 Editor::set_follow_playhead (bool yn, bool catch_up)
3746 if (_follow_playhead != yn) {
3747 if ((_follow_playhead = yn) == true && catch_up) {
3749 reset_x_origin_to_follow_playhead ();
3756 Editor::toggle_stationary_playhead ()
3758 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3760 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3761 set_stationary_playhead (tact->get_active());
3766 Editor::set_stationary_playhead (bool yn)
3768 if (_stationary_playhead != yn) {
3769 if ((_stationary_playhead = yn) == true) {
3771 // FIXME need a 3.0 equivalent of this 2.X call
3772 // update_current_screen ();
3779 Editor::playlist_selector () const
3781 return *_playlist_selector;
3785 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3789 switch (_snap_type) {
3794 case SnapToBeatDiv128:
3797 case SnapToBeatDiv64:
3800 case SnapToBeatDiv32:
3803 case SnapToBeatDiv28:
3806 case SnapToBeatDiv24:
3809 case SnapToBeatDiv20:
3812 case SnapToBeatDiv16:
3815 case SnapToBeatDiv14:
3818 case SnapToBeatDiv12:
3821 case SnapToBeatDiv10:
3824 case SnapToBeatDiv8:
3827 case SnapToBeatDiv7:
3830 case SnapToBeatDiv6:
3833 case SnapToBeatDiv5:
3836 case SnapToBeatDiv4:
3839 case SnapToBeatDiv3:
3842 case SnapToBeatDiv2:
3848 return _session->tempo_map().meter_at (position).divisions_per_bar();
3853 case SnapToTimecodeFrame:
3854 case SnapToTimecodeSeconds:
3855 case SnapToTimecodeMinutes:
3858 case SnapToRegionStart:
3859 case SnapToRegionEnd:
3860 case SnapToRegionSync:
3861 case SnapToRegionBoundary:
3871 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3875 ret = nudge_clock->current_duration (pos);
3876 next = ret + 1; /* XXXX fix me */
3882 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3884 ArdourDialog dialog (_("Playlist Deletion"));
3885 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3886 "If it is kept, its audio files will not be cleaned.\n"
3887 "If it is deleted, audio files used by it alone will be cleaned."),
3890 dialog.set_position (WIN_POS_CENTER);
3891 dialog.get_vbox()->pack_start (label);
3895 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3896 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3897 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3899 switch (dialog.run ()) {
3900 case RESPONSE_ACCEPT:
3901 /* delete the playlist */
3905 case RESPONSE_REJECT:
3906 /* keep the playlist */
3918 Editor::audio_region_selection_covers (framepos_t where)
3920 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3921 if ((*a)->region()->covers (where)) {
3930 Editor::prepare_for_cleanup ()
3932 cut_buffer->clear_regions ();
3933 cut_buffer->clear_playlists ();
3935 selection->clear_regions ();
3936 selection->clear_playlists ();
3938 _regions->suspend_redisplay ();
3942 Editor::finish_cleanup ()
3944 _regions->resume_redisplay ();
3948 Editor::transport_loop_location()
3951 return _session->locations()->auto_loop_location();
3958 Editor::transport_punch_location()
3961 return _session->locations()->auto_punch_location();
3968 Editor::control_layout_scroll (GdkEventScroll* ev)
3970 if (Keyboard::some_magic_widget_has_focus()) {
3974 switch (ev->direction) {
3976 scroll_tracks_up_line ();
3980 case GDK_SCROLL_DOWN:
3981 scroll_tracks_down_line ();
3985 /* no left/right handling yet */
3993 Editor::session_state_saved (string)
3996 _snapshots->redisplay ();
4000 Editor::update_tearoff_visibility()
4002 bool visible = Config->get_keep_tearoffs();
4003 _mouse_mode_tearoff->set_visible (visible);
4004 _tools_tearoff->set_visible (visible);
4005 _zoom_tearoff->set_visible (visible);
4009 Editor::maximise_editing_space ()
4021 Editor::restore_editing_space ()
4033 * Make new playlists for a given track and also any others that belong
4034 * to the same active route group with the `select' property.
4039 Editor::new_playlists (TimeAxisView* v)
4041 begin_reversible_command (_("new 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_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4045 commit_reversible_command ();
4049 * Use a copy of the current playlist for a given track and also any others that belong
4050 * to the same active route group with the `select' property.
4055 Editor::copy_playlists (TimeAxisView* v)
4057 begin_reversible_command (_("copy playlists"));
4058 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4059 _session->playlists->get (playlists);
4060 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4061 commit_reversible_command ();
4064 /** Clear the current playlist for a given track and also any others that belong
4065 * to the same active route group with the `select' property.
4070 Editor::clear_playlists (TimeAxisView* v)
4072 begin_reversible_command (_("clear playlists"));
4073 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4074 _session->playlists->get (playlists);
4075 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4076 commit_reversible_command ();
4080 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4082 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4086 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4088 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4092 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4094 atv.clear_playlist ();
4098 Editor::on_key_press_event (GdkEventKey* ev)
4100 return key_press_focus_accelerator_handler (*this, ev);
4104 Editor::on_key_release_event (GdkEventKey* ev)
4106 return Gtk::Window::on_key_release_event (ev);
4107 // return key_press_focus_accelerator_handler (*this, ev);
4110 /** Queue up a change to the viewport x origin.
4111 * @param frame New x origin.
4114 Editor::reset_x_origin (framepos_t frame)
4116 pending_visual_change.add (VisualChange::TimeOrigin);
4117 pending_visual_change.time_origin = frame;
4118 ensure_visual_change_idle_handler ();
4122 Editor::reset_y_origin (double y)
4124 pending_visual_change.add (VisualChange::YOrigin);
4125 pending_visual_change.y_origin = y;
4126 ensure_visual_change_idle_handler ();
4130 Editor::reset_zoom (double fpp)
4132 clamp_frames_per_pixel (fpp);
4134 if (fpp == frames_per_pixel) {
4138 pending_visual_change.add (VisualChange::ZoomLevel);
4139 pending_visual_change.frames_per_pixel = fpp;
4140 ensure_visual_change_idle_handler ();
4144 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4146 reset_x_origin (frame);
4149 if (!no_save_visual) {
4150 undo_visual_stack.push_back (current_visual_state(false));
4154 Editor::VisualState::VisualState (bool with_tracks)
4155 : gui_state (with_tracks ? new GUIObjectState : 0)
4159 Editor::VisualState::~VisualState ()
4164 Editor::VisualState*
4165 Editor::current_visual_state (bool with_tracks)
4167 VisualState* vs = new VisualState (with_tracks);
4168 vs->y_position = vertical_adjustment.get_value();
4169 vs->frames_per_pixel = frames_per_pixel;
4170 vs->leftmost_frame = leftmost_frame;
4171 vs->zoom_focus = zoom_focus;
4174 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4181 Editor::undo_visual_state ()
4183 if (undo_visual_stack.empty()) {
4187 VisualState* vs = undo_visual_stack.back();
4188 undo_visual_stack.pop_back();
4191 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4193 use_visual_state (*vs);
4197 Editor::redo_visual_state ()
4199 if (redo_visual_stack.empty()) {
4203 VisualState* vs = redo_visual_stack.back();
4204 redo_visual_stack.pop_back();
4206 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4208 use_visual_state (*vs);
4212 Editor::swap_visual_state ()
4214 if (undo_visual_stack.empty()) {
4215 redo_visual_state ();
4217 undo_visual_state ();
4222 Editor::use_visual_state (VisualState& vs)
4224 PBD::Unwinder<bool> nsv (no_save_visual, true);
4226 _routes->suspend_redisplay ();
4228 vertical_adjustment.set_value (vs.y_position);
4230 set_zoom_focus (vs.zoom_focus);
4231 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_pixel);
4234 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4236 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4237 (*i)->reset_visual_state ();
4241 _routes->update_visibility ();
4242 _routes->resume_redisplay ();
4245 /** This is the core function that controls the zoom level of the canvas. It is called
4246 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4247 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4250 Editor::set_frames_per_pixel (double fpp)
4253 tempo_lines->tempo_map_changed();
4256 frames_per_pixel = fpp;
4258 /* convert fpu to frame count */
4260 framepos_t frames = (framepos_t) floor (frames_per_pixel * _visible_canvas_width);
4262 if (frames_per_pixel != zoom_range_clock->current_duration()) {
4263 zoom_range_clock->set (frames);
4266 bool const showing_time_selection = selection->time.length() > 0;
4268 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4269 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4270 (*i)->reshow_selection (selection->time);
4274 ZoomChanged (); /* EMIT_SIGNAL */
4276 //reset_scrolling_region ();
4278 if (playhead_cursor) {
4279 playhead_cursor->set_position (playhead_cursor->current_frame ());
4282 refresh_location_display();
4283 _summary->set_overlays_dirty ();
4285 update_marker_labels ();
4291 Editor::queue_visual_videotimeline_update ()
4294 * pending_visual_change.add (VisualChange::VideoTimeline);
4295 * or maybe even more specific: which videotimeline-image
4296 * currently it calls update_video_timeline() to update
4297 * _all outdated_ images on the video-timeline.
4298 * see 'exposeimg()' in video_image_frame.cc
4300 ensure_visual_change_idle_handler ();
4304 Editor::ensure_visual_change_idle_handler ()
4306 if (pending_visual_change.idle_handler_id < 0) {
4307 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4308 pending_visual_change.being_handled = false;
4313 Editor::_idle_visual_changer (void* arg)
4315 return static_cast<Editor*>(arg)->idle_visual_changer ();
4319 Editor::idle_visual_changer ()
4321 /* set_horizontal_position() below (and maybe other calls) call
4322 gtk_main_iteration(), so it's possible that a signal will be handled
4323 half-way through this method. If this signal wants an
4324 idle_visual_changer we must schedule another one after this one, so
4325 mark the idle_handler_id as -1 here to allow that. Also make a note
4326 that we are doing the visual change, so that changes in response to
4327 super-rapid-screen-update can be dropped if we are still processing
4331 pending_visual_change.idle_handler_id = -1;
4332 pending_visual_change.being_handled = true;
4334 VisualChange::Type p = pending_visual_change.pending;
4335 pending_visual_change.pending = (VisualChange::Type) 0;
4337 double const last_time_origin = horizontal_position ();
4339 if (p & VisualChange::ZoomLevel) {
4340 set_frames_per_pixel (pending_visual_change.frames_per_pixel);
4342 compute_fixed_ruler_scale ();
4344 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4345 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4347 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4348 current_bbt_points_begin, current_bbt_points_end);
4349 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4350 current_bbt_points_begin, current_bbt_points_end);
4351 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4354 if (p & VisualChange::ZoomLevel) {
4355 update_video_timeline();
4358 if (p & VisualChange::TimeOrigin) {
4359 set_horizontal_position (pending_visual_change.time_origin / frames_per_pixel);
4362 if (p & VisualChange::YOrigin) {
4363 vertical_adjustment.set_value (pending_visual_change.y_origin);
4366 if (last_time_origin == horizontal_position ()) {
4367 /* changed signal not emitted */
4368 update_fixed_rulers ();
4369 redisplay_tempo (true);
4372 if (!(p & VisualChange::ZoomLevel)) {
4373 update_video_timeline();
4376 _summary->set_overlays_dirty ();
4378 pending_visual_change.being_handled = false;
4379 return 0; /* this is always a one-shot call */
4382 struct EditorOrderTimeAxisSorter {
4383 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4384 return a->order () < b->order ();
4389 Editor::sort_track_selection (TrackViewList& sel)
4391 EditorOrderTimeAxisSorter cmp;
4396 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4399 framepos_t where = 0;
4400 EditPoint ep = _edit_point;
4402 if (from_context_menu && (ep == EditAtMouse)) {
4403 return window_event_frame (&context_click_event, 0, 0);
4406 if (entered_marker) {
4407 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4408 return entered_marker->position();
4411 if (ignore_playhead && ep == EditAtPlayhead) {
4412 ep = EditAtSelectedMarker;
4416 case EditAtPlayhead:
4417 where = _session->audible_frame();
4418 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4421 case EditAtSelectedMarker:
4422 if (!selection->markers.empty()) {
4424 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4427 where = loc->start();
4431 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4439 if (!mouse_frame (where, ignored)) {
4440 /* XXX not right but what can we do ? */
4444 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4452 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4454 if (!_session) return;
4456 begin_reversible_command (cmd);
4460 if ((tll = transport_loop_location()) == 0) {
4461 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4462 XMLNode &before = _session->locations()->get_state();
4463 _session->locations()->add (loc, true);
4464 _session->set_auto_loop_location (loc);
4465 XMLNode &after = _session->locations()->get_state();
4466 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4468 XMLNode &before = tll->get_state();
4469 tll->set_hidden (false, this);
4470 tll->set (start, end);
4471 XMLNode &after = tll->get_state();
4472 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4475 commit_reversible_command ();
4479 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4481 if (!_session) return;
4483 begin_reversible_command (cmd);
4487 if ((tpl = transport_punch_location()) == 0) {
4488 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4489 XMLNode &before = _session->locations()->get_state();
4490 _session->locations()->add (loc, true);
4491 _session->set_auto_loop_location (loc);
4492 XMLNode &after = _session->locations()->get_state();
4493 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4496 XMLNode &before = tpl->get_state();
4497 tpl->set_hidden (false, this);
4498 tpl->set (start, end);
4499 XMLNode &after = tpl->get_state();
4500 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4503 commit_reversible_command ();
4506 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4507 * @param rs List to which found regions are added.
4508 * @param where Time to look at.
4509 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4512 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4514 const TrackViewList* tracks;
4517 tracks = &track_views;
4522 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4524 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4527 boost::shared_ptr<Track> tr;
4528 boost::shared_ptr<Playlist> pl;
4530 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4532 boost::shared_ptr<RegionList> regions = pl->regions_at (
4533 (framepos_t) floor ( (double) where * tr->speed()));
4535 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4536 RegionView* rv = rtv->view()->find_view (*i);
4547 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4549 const TrackViewList* tracks;
4552 tracks = &track_views;
4557 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4558 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4560 boost::shared_ptr<Track> tr;
4561 boost::shared_ptr<Playlist> pl;
4563 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4565 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4566 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4568 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4570 RegionView* rv = rtv->view()->find_view (*i);
4581 /** Get regions using the following method:
4583 * Make a region list using the selected regions, unless
4584 * the edit point is `mouse' and the mouse is over an unselected
4585 * region. In this case, use just that region.
4587 * If the edit point is not 'mouse', and there are no regions selected,
4588 * search the list of selected tracks and return regions that are under
4589 * the edit point on these tracks. If there are no selected tracks and
4590 * 'No Selection = All Tracks' is active, search all tracks,
4592 * The rationale here is that the mouse edit point is special in that
4593 * its position describes both a time and a track; the other edit
4594 * modes only describe a time. Hence if the edit point is `mouse' we
4595 * ignore selected tracks, as we assume the user means something by
4596 * pointing at a particular track. Also in this case we take note of
4597 * the region directly under the edit point, as there is always just one
4598 * (rather than possibly several with non-mouse edit points).
4602 Editor::get_regions_from_selection_and_edit_point ()
4604 RegionSelection regions;
4606 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4607 regions.add (entered_regionview);
4609 regions = selection->regions;
4613 if (regions.empty() && _edit_point != EditAtMouse) {
4614 TrackViewList tracks = selection->tracks;
4616 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4617 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4618 * is enabled, so consider all tracks
4620 tracks = track_views;
4623 if (!tracks.empty()) {
4624 /* no region selected or entered, but some selected tracks:
4625 * act on all regions on the selected tracks at the edit point
4627 framepos_t const where = get_preferred_edit_position ();
4628 get_regions_at(regions, where, tracks);
4634 /** Start with regions that are selected, or the entered regionview if none are selected.
4635 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4636 * of the regions that we started with.
4640 Editor::get_regions_from_selection_and_entered ()
4642 RegionSelection regions = selection->regions;
4644 if (regions.empty() && entered_regionview) {
4645 regions.add (entered_regionview);
4652 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4654 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4656 RouteTimeAxisView* tatv;
4658 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4660 boost::shared_ptr<Playlist> pl;
4661 vector<boost::shared_ptr<Region> > results;
4663 boost::shared_ptr<Track> tr;
4665 if ((tr = tatv->track()) == 0) {
4670 if ((pl = (tr->playlist())) != 0) {
4671 if (src_comparison) {
4672 pl->get_source_equivalent_regions (region, results);
4674 pl->get_region_list_equivalent_regions (region, results);
4678 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4679 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4680 regions.push_back (marv);
4689 Editor::show_rhythm_ferret ()
4691 if (rhythm_ferret == 0) {
4692 rhythm_ferret = new RhythmFerret(*this);
4695 rhythm_ferret->set_session (_session);
4696 rhythm_ferret->show ();
4697 rhythm_ferret->present ();
4701 Editor::first_idle ()
4703 MessageDialog* dialog = 0;
4705 if (track_views.size() > 1) {
4706 dialog = new MessageDialog (
4708 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4712 ARDOUR_UI::instance()->flush_pending ();
4715 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4719 // first idle adds route children (automation tracks), so we need to redisplay here
4720 _routes->redisplay ();
4727 Editor::_idle_resize (gpointer arg)
4729 return ((Editor*)arg)->idle_resize ();
4733 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4735 if (resize_idle_id < 0) {
4736 resize_idle_id = g_idle_add (_idle_resize, this);
4737 _pending_resize_amount = 0;
4740 /* make a note of the smallest resulting height, so that we can clamp the
4741 lower limit at TimeAxisView::hSmall */
4743 int32_t min_resulting = INT32_MAX;
4745 _pending_resize_amount += h;
4746 _pending_resize_view = view;
4748 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4750 if (selection->tracks.contains (_pending_resize_view)) {
4751 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4752 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4756 if (min_resulting < 0) {
4761 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4762 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4766 /** Handle pending resizing of tracks */
4768 Editor::idle_resize ()
4770 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4772 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4773 selection->tracks.contains (_pending_resize_view)) {
4775 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4776 if (*i != _pending_resize_view) {
4777 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4782 _pending_resize_amount = 0;
4784 _group_tabs->set_dirty ();
4785 resize_idle_id = -1;
4793 ENSURE_GUI_THREAD (*this, &Editor::located);
4796 playhead_cursor->set_position (_session->audible_frame ());
4797 if (_follow_playhead && !_pending_initial_locate) {
4798 reset_x_origin_to_follow_playhead ();
4802 _pending_locate_request = false;
4803 _pending_initial_locate = false;
4807 Editor::region_view_added (RegionView *)
4809 _summary->set_dirty ();
4813 Editor::region_view_removed ()
4815 _summary->set_dirty ();
4819 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4821 TrackViewList::const_iterator j = track_views.begin ();
4822 while (j != track_views.end()) {
4823 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4824 if (rtv && rtv->route() == r) {
4835 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4839 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4840 TimeAxisView* tv = axis_view_from_route (*i);
4850 Editor::add_routes (RouteList& routes)
4852 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4854 RouteTimeAxisView *rtv;
4855 list<RouteTimeAxisView*> new_views;
4857 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4858 boost::shared_ptr<Route> route = (*x);
4860 if (route->is_auditioner() || route->is_monitor()) {
4864 DataType dt = route->input()->default_type();
4866 if (dt == ARDOUR::DataType::AUDIO) {
4867 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4868 rtv->set_route (route);
4869 } else if (dt == ARDOUR::DataType::MIDI) {
4870 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4871 rtv->set_route (route);
4873 throw unknown_type();
4876 new_views.push_back (rtv);
4877 track_views.push_back (rtv);
4879 rtv->effective_gain_display ();
4881 if (internal_editing()) {
4882 rtv->enter_internal_edit_mode ();
4884 rtv->leave_internal_edit_mode ();
4887 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4888 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4891 _routes->routes_added (new_views);
4892 _summary->routes_added (new_views);
4894 if (show_editor_mixer_when_tracks_arrive) {
4895 show_editor_mixer (true);
4898 editor_list_button.set_sensitive (true);
4902 Editor::timeaxisview_deleted (TimeAxisView *tv)
4904 if (_session && _session->deletion_in_progress()) {
4905 /* the situation is under control */
4909 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4911 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4913 _routes->route_removed (tv);
4915 if (tv == entered_track) {
4919 TimeAxisView::Children c = tv->get_child_list ();
4920 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4921 if (entered_track == i->get()) {
4926 /* remove it from the list of track views */
4928 TrackViewList::iterator i;
4930 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4931 i = track_views.erase (i);
4934 /* update whatever the current mixer strip is displaying, if revelant */
4936 boost::shared_ptr<Route> route;
4939 route = rtav->route ();
4942 if (current_mixer_strip && current_mixer_strip->route() == route) {
4944 TimeAxisView* next_tv;
4946 if (track_views.empty()) {
4948 } else if (i == track_views.end()) {
4949 next_tv = track_views.front();
4956 set_selected_mixer_strip (*next_tv);
4958 /* make the editor mixer strip go away setting the
4959 * button to inactive (which also unticks the menu option)
4962 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4968 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4970 if (apply_to_selection) {
4971 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4973 TrackSelection::iterator j = i;
4976 hide_track_in_display (*i, false);
4981 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4983 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4984 // this will hide the mixer strip
4985 set_selected_mixer_strip (*tv);
4988 _routes->hide_track_in_display (*tv);
4993 Editor::sync_track_view_list_and_routes ()
4995 track_views = TrackViewList (_routes->views ());
4997 _summary->set_dirty ();
4998 _group_tabs->set_dirty ();
5000 return false; // do not call again (until needed)
5004 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5006 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5011 /** Find a RouteTimeAxisView by the ID of its route */
5013 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5015 RouteTimeAxisView* v;
5017 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5018 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5019 if(v->route()->id() == id) {
5029 Editor::fit_route_group (RouteGroup *g)
5031 TrackViewList ts = axis_views_from_routes (g->route_list ());
5036 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5038 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5041 _session->cancel_audition ();
5045 if (_session->is_auditioning()) {
5046 _session->cancel_audition ();
5047 if (r == last_audition_region) {
5052 _session->audition_region (r);
5053 last_audition_region = r;
5058 Editor::hide_a_region (boost::shared_ptr<Region> r)
5060 r->set_hidden (true);
5064 Editor::show_a_region (boost::shared_ptr<Region> r)
5066 r->set_hidden (false);
5070 Editor::audition_region_from_region_list ()
5072 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5076 Editor::hide_region_from_region_list ()
5078 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5082 Editor::show_region_in_region_list ()
5084 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5088 Editor::step_edit_status_change (bool yn)
5091 start_step_editing ();
5093 stop_step_editing ();
5098 Editor::start_step_editing ()
5100 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5104 Editor::stop_step_editing ()
5106 step_edit_connection.disconnect ();
5110 Editor::check_step_edit ()
5112 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5113 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5115 mtv->check_step_edit ();
5119 return true; // do it again, till we stop
5123 Editor::scroll_press (Direction dir)
5125 ++_scroll_callbacks;
5127 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5128 /* delay the first auto-repeat */
5134 scroll_backward (1);
5142 scroll_tracks_up_line ();
5146 scroll_tracks_down_line ();
5150 /* do hacky auto-repeat */
5151 if (!_scroll_connection.connected ()) {
5153 _scroll_connection = Glib::signal_timeout().connect (
5154 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5157 _scroll_callbacks = 0;
5164 Editor::scroll_release ()
5166 _scroll_connection.disconnect ();
5169 /** Queue a change for the Editor viewport x origin to follow the playhead */
5171 Editor::reset_x_origin_to_follow_playhead ()
5173 framepos_t const frame = playhead_cursor->current_frame ();
5175 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5177 if (_session->transport_speed() < 0) {
5179 if (frame > (current_page_frames() / 2)) {
5180 center_screen (frame-(current_page_frames()/2));
5182 center_screen (current_page_frames()/2);
5189 if (frame < leftmost_frame) {
5191 if (_session->transport_rolling()) {
5192 /* rolling; end up with the playhead at the right of the page */
5193 l = frame - current_page_frames ();
5195 /* not rolling: end up with the playhead 1/4 of the way along the page */
5196 l = frame - current_page_frames() / 4;
5200 if (_session->transport_rolling()) {
5201 /* rolling: end up with the playhead on the left of the page */
5204 /* not rolling: end up with the playhead 3/4 of the way along the page */
5205 l = frame - 3 * current_page_frames() / 4;
5213 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5219 Editor::super_rapid_screen_update ()
5221 if (!_session || !_session->engine().running()) {
5225 /* METERING / MIXER STRIPS */
5227 /* update track meters, if required */
5228 if (is_mapped() && meters_running) {
5229 RouteTimeAxisView* rtv;
5230 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5231 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5232 rtv->fast_update ();
5237 /* and any current mixer strip */
5238 if (current_mixer_strip) {
5239 current_mixer_strip->fast_update ();
5242 /* PLAYHEAD AND VIEWPORT */
5244 framepos_t const frame = _session->audible_frame();
5246 /* There are a few reasons why we might not update the playhead / viewport stuff:
5248 * 1. we don't update things when there's a pending locate request, otherwise
5249 * when the editor requests a locate there is a chance that this method
5250 * will move the playhead before the locate request is processed, causing
5252 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5253 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5256 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5258 last_update_frame = frame;
5260 if (!_dragging_playhead) {
5261 playhead_cursor->set_position (frame);
5264 if (!_stationary_playhead) {
5266 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5267 /* We only do this if we aren't already
5268 handling a visual change (ie if
5269 pending_visual_change.being_handled is
5270 false) so that these requests don't stack
5271 up there are too many of them to handle in
5274 reset_x_origin_to_follow_playhead ();
5279 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5283 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5284 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_pixel;
5285 if (target <= 0.0) {
5288 if (fabs(target - current) < current_page_frames() / frames_per_pixel) {
5289 target = (target * 0.15) + (current * 0.85);
5295 set_horizontal_position (current);
5304 Editor::session_going_away ()
5306 _have_idled = false;
5308 _session_connections.drop_connections ();
5310 super_rapid_screen_update_connection.disconnect ();
5312 selection->clear ();
5313 cut_buffer->clear ();
5315 clicked_regionview = 0;
5316 clicked_axisview = 0;
5317 clicked_routeview = 0;
5318 entered_regionview = 0;
5320 last_update_frame = 0;
5323 playhead_cursor->hide ();
5325 /* rip everything out of the list displays */
5329 _route_groups->clear ();
5331 /* do this first so that deleting a track doesn't reset cms to null
5332 and thus cause a leak.
5335 if (current_mixer_strip) {
5336 if (current_mixer_strip->get_parent() != 0) {
5337 global_hpacker.remove (*current_mixer_strip);
5339 delete current_mixer_strip;
5340 current_mixer_strip = 0;
5343 /* delete all trackviews */
5345 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5348 track_views.clear ();
5350 zoom_range_clock->set_session (0);
5351 nudge_clock->set_session (0);
5353 editor_list_button.set_active(false);
5354 editor_list_button.set_sensitive(false);
5356 /* clear tempo/meter rulers */
5357 remove_metric_marks ();
5359 clear_marker_display ();
5361 stop_step_editing ();
5363 /* get rid of any existing editor mixer strip */
5365 WindowTitle title(Glib::get_application_name());
5366 title += _("Editor");
5368 set_title (title.get_string());
5370 SessionHandlePtr::session_going_away ();
5375 Editor::show_editor_list (bool yn)
5378 _the_notebook.show ();
5380 _the_notebook.hide ();
5385 Editor::change_region_layering_order (bool from_context_menu)
5387 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5389 if (!clicked_routeview) {
5390 if (layering_order_editor) {
5391 layering_order_editor->hide ();
5396 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5402 boost::shared_ptr<Playlist> pl = track->playlist();
5408 if (layering_order_editor == 0) {
5409 layering_order_editor = new RegionLayeringOrderEditor (*this);
5410 layering_order_editor->set_position (WIN_POS_MOUSE);
5413 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5414 layering_order_editor->maybe_present ();
5418 Editor::update_region_layering_order_editor ()
5420 if (layering_order_editor && layering_order_editor->is_visible ()) {
5421 change_region_layering_order (true);
5426 Editor::setup_fade_images ()
5428 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5429 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5430 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5431 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5432 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5434 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5435 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5436 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5437 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5438 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5440 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5441 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5442 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5443 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5444 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5446 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5447 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5448 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5449 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5450 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5454 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5456 Editor::action_menu_item (std::string const & name)
5458 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5461 return *manage (a->create_menu_item ());
5465 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5467 EventBox* b = manage (new EventBox);
5468 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5469 Label* l = manage (new Label (name));
5473 _the_notebook.append_page (widget, *b);
5477 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5479 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5480 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5483 if (ev->type == GDK_2BUTTON_PRESS) {
5485 /* double-click on a notebook tab shrinks or expands the notebook */
5487 if (_notebook_shrunk) {
5488 if (pre_notebook_shrink_pane_width) {
5489 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5491 _notebook_shrunk = false;
5493 pre_notebook_shrink_pane_width = edit_pane.get_position();
5495 /* this expands the LHS of the edit pane to cover the notebook
5496 PAGE but leaves the tabs visible.
5498 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5499 _notebook_shrunk = true;
5507 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5509 using namespace Menu_Helpers;
5511 MenuList& items = _control_point_context_menu.items ();
5514 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5515 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5516 if (!can_remove_control_point (item)) {
5517 items.back().set_sensitive (false);
5520 _control_point_context_menu.popup (event->button.button, event->button.time);
5524 Editor::shift_key_released ()
5526 _stepping_axis_view = 0;
5531 Editor::save_canvas_state ()
5533 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5534 string path = string_compose ("%1/canvas-state.xml", _session->path());