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 /* these enable us to have a dedicated window (for cursor setting, etc.)
517 for the canvas areas.
520 track_canvas_event_box.add (*_track_canvas_viewport);
522 time_canvas_event_box.add (time_canvas_vbox);
523 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
525 edit_packer.set_col_spacings (0);
526 edit_packer.set_row_spacings (0);
527 edit_packer.set_homogeneous (false);
528 edit_packer.set_border_width (0);
529 edit_packer.set_name ("EditorWindow");
531 /* labels for the rulers */
532 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
533 /* labels for the marker "tracks" (time bars) */
534 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
536 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
538 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
539 /* time bars canvas */
540 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
542 edit_packer.attach (track_canvas_event_box, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
544 bottom_hbox.set_border_width (2);
545 bottom_hbox.set_spacing (3);
547 _route_groups = new EditorRouteGroups (this);
548 _routes = new EditorRoutes (this);
549 _regions = new EditorRegions (this);
550 _snapshots = new EditorSnapshots (this);
551 _locations = new EditorLocations (this);
553 add_notebook_page (_("Regions"), _regions->widget ());
554 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
555 add_notebook_page (_("Snapshots"), _snapshots->widget ());
556 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
557 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
559 _the_notebook.set_show_tabs (true);
560 _the_notebook.set_scrollable (true);
561 _the_notebook.popup_disable ();
562 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
563 _the_notebook.show_all ();
565 _notebook_shrunk = false;
567 editor_summary_pane.pack1(edit_packer);
569 Button* summary_arrows_left_left = manage (new Button);
570 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
571 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
572 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
574 Button* summary_arrows_left_right = manage (new Button);
575 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
576 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
577 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
579 VBox* summary_arrows_left = manage (new VBox);
580 summary_arrows_left->pack_start (*summary_arrows_left_left);
581 summary_arrows_left->pack_start (*summary_arrows_left_right);
583 Button* summary_arrows_right_up = manage (new Button);
584 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
585 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
586 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 Button* summary_arrows_right_down = manage (new Button);
589 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
590 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
591 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
593 VBox* summary_arrows_right = manage (new VBox);
594 summary_arrows_right->pack_start (*summary_arrows_right_up);
595 summary_arrows_right->pack_start (*summary_arrows_right_down);
597 Frame* summary_frame = manage (new Frame);
598 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
600 summary_frame->add (*_summary);
601 summary_frame->show ();
603 _summary_hbox.pack_start (*summary_arrows_left, false, false);
604 _summary_hbox.pack_start (*summary_frame, true, true);
605 _summary_hbox.pack_start (*summary_arrows_right, false, false);
607 editor_summary_pane.pack2 (_summary_hbox);
609 edit_pane.pack1 (editor_summary_pane, true, true);
610 edit_pane.pack2 (_the_notebook, false, true);
612 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
614 /* XXX: editor_summary_pane might need similar to the edit_pane */
616 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
618 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
619 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
621 top_hbox.pack_start (toolbar_frame);
623 HBox *hbox = manage (new HBox);
624 hbox->pack_start (edit_pane, true, true);
626 global_vpacker.pack_start (top_hbox, false, false);
627 global_vpacker.pack_start (*hbox, true, true);
629 global_hpacker.pack_start (global_vpacker, true, true);
631 set_name ("EditorWindow");
632 add_accel_group (ActionManager::ui_manager->get_accel_group());
634 status_bar_hpacker.show ();
636 vpacker.pack_end (status_bar_hpacker, false, false);
637 vpacker.pack_end (global_hpacker, true, true);
639 /* register actions now so that set_state() can find them and set toggles/checks etc */
642 /* when we start using our own keybinding system for the editor, this
643 * will be uncommented
649 _snap_type = SnapToBeat;
650 set_snap_to (_snap_type);
651 _snap_mode = SnapOff;
652 set_snap_mode (_snap_mode);
653 set_mouse_mode (MouseObject, true);
654 pre_internal_mouse_mode = MouseObject;
655 pre_internal_snap_type = _snap_type;
656 pre_internal_snap_mode = _snap_mode;
657 internal_snap_type = _snap_type;
658 internal_snap_mode = _snap_mode;
659 set_edit_point_preference (EditAtMouse, true);
661 _playlist_selector = new PlaylistSelector();
662 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
664 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
668 nudge_forward_button.set_name ("zoom button");
669 nudge_forward_button.add_elements (ArdourButton::FlatFace);
670 nudge_forward_button.set_image(::get_icon("nudge_right"));
672 nudge_backward_button.set_name ("zoom button");
673 nudge_backward_button.add_elements (ArdourButton::FlatFace);
674 nudge_backward_button.set_image(::get_icon("nudge_left"));
676 fade_context_menu.set_name ("ArdourContextMenu");
678 /* icons, titles, WM stuff */
680 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
681 Glib::RefPtr<Gdk::Pixbuf> icon;
683 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
684 window_icons.push_back (icon);
686 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
687 window_icons.push_back (icon);
689 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
690 window_icons.push_back (icon);
692 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
693 window_icons.push_back (icon);
695 if (!window_icons.empty()) {
696 // set_icon_list (window_icons);
697 set_default_icon_list (window_icons);
700 WindowTitle title(Glib::get_application_name());
701 title += _("Editor");
702 set_title (title.get_string());
703 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
706 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
708 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
709 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
711 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
713 /* allow external control surfaces/protocols to do various things */
715 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
716 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
717 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
718 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
719 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
720 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
721 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
722 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
723 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
724 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
725 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
726 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
727 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
728 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
730 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
731 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
732 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
733 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
734 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
736 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
738 /* problematic: has to return a value and thus cannot be x-thread */
740 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
742 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
744 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
746 _ignore_region_action = false;
747 _last_region_menu_was_main = false;
748 _popup_region_menu_item = 0;
750 _show_marker_lines = false;
751 _over_region_trim_target = false;
753 /* Button bindings */
755 button_bindings = new Bindings;
757 XMLNode* node = button_settings();
759 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
760 button_bindings->load (**i);
767 setup_fade_images ();
773 if(image_socket_listener) {
774 if(image_socket_listener->is_connected())
776 image_socket_listener->close_connection() ;
779 delete image_socket_listener ;
780 image_socket_listener = 0 ;
784 delete button_bindings;
786 delete _route_groups;
787 delete _track_canvas_viewport;
792 Editor::button_settings () const
794 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
795 XMLNode* node = find_named_node (*settings, X_("Buttons"));
798 node = new XMLNode (X_("Buttons"));
805 Editor::add_toplevel_controls (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::get_smart_mode () const
814 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
818 Editor::catch_vanishing_regionview (RegionView *rv)
820 /* note: the selection will take care of the vanishing
821 audioregionview by itself.
824 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
828 if (clicked_regionview == rv) {
829 clicked_regionview = 0;
832 if (entered_regionview == rv) {
833 set_entered_regionview (0);
836 if (!_all_region_actions_sensitized) {
837 sensitize_all_region_actions (true);
840 _over_region_trim_target = false;
844 Editor::set_entered_regionview (RegionView* rv)
846 if (rv == entered_regionview) {
850 if (entered_regionview) {
851 entered_regionview->exited ();
854 if ((entered_regionview = rv) != 0) {
855 entered_regionview->entered (internal_editing ());
858 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
859 /* This RegionView entry might have changed what region actions
860 are allowed, so sensitize them all in case a key is pressed.
862 sensitize_all_region_actions (true);
867 Editor::set_entered_track (TimeAxisView* tav)
870 entered_track->exited ();
873 if ((entered_track = tav) != 0) {
874 entered_track->entered ();
879 Editor::show_window ()
881 if (!is_visible ()) {
884 /* XXX: this is a bit unfortunate; it would probably
885 be nicer if we could just call show () above rather
886 than needing the show_all ()
889 /* re-hide stuff if necessary */
890 editor_list_button_toggled ();
891 parameter_changed ("show-summary");
892 parameter_changed ("show-group-tabs");
893 parameter_changed ("show-zoom-tools");
895 /* now reset all audio_time_axis heights, because widgets might need
901 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
902 tv = (static_cast<TimeAxisView*>(*i));
906 if (current_mixer_strip) {
907 current_mixer_strip->hide_things ();
908 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
916 Editor::instant_save ()
918 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
923 _session->add_instant_xml(get_state());
925 Config->add_instant_xml(get_state());
930 Editor::zoom_adjustment_changed ()
936 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
937 bool clamped = clamp_frames_per_pixel (fpu);
940 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
947 Editor::control_vertical_zoom_in_all ()
949 tav_zoom_smooth (false, true);
953 Editor::control_vertical_zoom_out_all ()
955 tav_zoom_smooth (true, true);
959 Editor::control_vertical_zoom_in_selected ()
961 tav_zoom_smooth (false, false);
965 Editor::control_vertical_zoom_out_selected ()
967 tav_zoom_smooth (true, false);
971 Editor::control_view (uint32_t view)
973 goto_visual_state (view);
977 Editor::control_unselect ()
979 selection->clear_tracks ();
983 Editor::control_select (uint32_t rid, Selection::Operation op)
985 /* handles the (static) signal from the ControlProtocol class that
986 * requests setting the selected track to a given RID
993 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
999 TimeAxisView* tav = axis_view_from_route (r);
1003 case Selection::Add:
1004 selection->add (tav);
1006 case Selection::Toggle:
1007 selection->toggle (tav);
1009 case Selection::Extend:
1011 case Selection::Set:
1012 selection->set (tav);
1016 selection->clear_tracks ();
1021 Editor::control_step_tracks_up ()
1023 scroll_tracks_up_line ();
1027 Editor::control_step_tracks_down ()
1029 scroll_tracks_down_line ();
1033 Editor::control_scroll (float fraction)
1035 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1041 double step = fraction * current_page_frames();
1044 _control_scroll_target is an optional<T>
1046 it acts like a pointer to an framepos_t, with
1047 a operator conversion to boolean to check
1048 that it has a value could possibly use
1049 playhead_cursor->current_frame to store the
1050 value and a boolean in the class to know
1051 when it's out of date
1054 if (!_control_scroll_target) {
1055 _control_scroll_target = _session->transport_frame();
1056 _dragging_playhead = true;
1059 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1060 *_control_scroll_target = 0;
1061 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1062 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1064 *_control_scroll_target += (framepos_t) floor (step);
1067 /* move visuals, we'll catch up with it later */
1069 playhead_cursor->set_position (*_control_scroll_target);
1070 UpdateAllTransportClocks (*_control_scroll_target);
1072 if (*_control_scroll_target > (current_page_frames() / 2)) {
1073 /* try to center PH in window */
1074 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1080 Now we do a timeout to actually bring the session to the right place
1081 according to the playhead. This is to avoid reading disk buffers on every
1082 call to control_scroll, which is driven by ScrollTimeline and therefore
1083 probably by a control surface wheel which can generate lots of events.
1085 /* cancel the existing timeout */
1087 control_scroll_connection.disconnect ();
1089 /* add the next timeout */
1091 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1095 Editor::deferred_control_scroll (framepos_t /*target*/)
1097 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1098 // reset for next stream
1099 _control_scroll_target = boost::none;
1100 _dragging_playhead = false;
1105 Editor::access_action (std::string action_group, std::string action_item)
1111 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1114 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1122 Editor::on_realize ()
1124 Window::on_realize ();
1129 Editor::map_position_change (framepos_t frame)
1131 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1133 if (_session == 0) {
1137 if (_follow_playhead) {
1138 center_screen (frame);
1141 playhead_cursor->set_position (frame);
1145 Editor::center_screen (framepos_t frame)
1147 double const page = _visible_canvas_width * frames_per_pixel;
1149 /* if we're off the page, then scroll.
1152 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1153 center_screen_internal (frame, page);
1158 Editor::center_screen_internal (framepos_t frame, float page)
1163 frame -= (framepos_t) page;
1168 reset_x_origin (frame);
1173 Editor::update_title ()
1175 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1178 bool dirty = _session->dirty();
1180 string session_name;
1182 if (_session->snap_name() != _session->name()) {
1183 session_name = _session->snap_name();
1185 session_name = _session->name();
1189 session_name = "*" + session_name;
1192 WindowTitle title(session_name);
1193 title += Glib::get_application_name();
1194 set_title (title.get_string());
1196 /* ::session_going_away() will have taken care of it */
1201 Editor::set_session (Session *t)
1203 SessionHandlePtr::set_session (t);
1209 zoom_range_clock->set_session (_session);
1210 _playlist_selector->set_session (_session);
1211 nudge_clock->set_session (_session);
1212 _summary->set_session (_session);
1213 _group_tabs->set_session (_session);
1214 _route_groups->set_session (_session);
1215 _regions->set_session (_session);
1216 _snapshots->set_session (_session);
1217 _routes->set_session (_session);
1218 _locations->set_session (_session);
1220 if (rhythm_ferret) {
1221 rhythm_ferret->set_session (_session);
1224 if (analysis_window) {
1225 analysis_window->set_session (_session);
1229 sfbrowser->set_session (_session);
1232 compute_fixed_ruler_scale ();
1234 /* Make sure we have auto loop and auto punch ranges */
1236 Location* loc = _session->locations()->auto_loop_location();
1238 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1240 if (loc->start() == loc->end()) {
1241 loc->set_end (loc->start() + 1);
1244 _session->locations()->add (loc, false);
1245 _session->set_auto_loop_location (loc);
1248 loc->set_name (_("Loop"));
1251 loc = _session->locations()->auto_punch_location();
1254 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1256 if (loc->start() == loc->end()) {
1257 loc->set_end (loc->start() + 1);
1260 _session->locations()->add (loc, false);
1261 _session->set_auto_punch_location (loc);
1264 loc->set_name (_("Punch"));
1267 refresh_location_display ();
1269 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1270 the selected Marker; this needs the LocationMarker list to be available.
1272 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1273 set_state (*node, Stateful::loading_state_version);
1275 /* catch up with the playhead */
1277 _session->request_locate (playhead_cursor->current_frame ());
1278 _pending_initial_locate = true;
1282 /* These signals can all be emitted by a non-GUI thread. Therefore the
1283 handlers for them must not attempt to directly interact with the GUI,
1284 but use Gtkmm2ext::UI::instance()->call_slot();
1287 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1288 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1289 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1290 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1291 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1292 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1293 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1294 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1295 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1296 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1297 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1298 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1299 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1300 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1302 playhead_cursor->show ();
1304 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1305 Config->map_parameters (pc);
1306 _session->config.map_parameters (pc);
1308 restore_ruler_visibility ();
1309 //tempo_map_changed (PropertyChange (0));
1310 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1312 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1313 (static_cast<TimeAxisView*>(*i))->set_frames_per_pixel (frames_per_pixel);
1316 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1317 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1320 switch (_snap_type) {
1321 case SnapToRegionStart:
1322 case SnapToRegionEnd:
1323 case SnapToRegionSync:
1324 case SnapToRegionBoundary:
1325 build_region_boundary_cache ();
1332 /* register for undo history */
1333 _session->register_with_memento_command_factory(id(), this);
1335 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1337 start_updating_meters ();
1341 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1343 if (a->get_name() == "RegionMenu") {
1344 /* When the main menu's region menu is opened, we setup the actions so that they look right
1345 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1346 so we resensitize all region actions when the entered regionview or the region selection
1347 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1348 happens after the region context menu is opened. So we set a flag here, too.
1352 sensitize_the_right_region_actions ();
1353 _last_region_menu_was_main = true;
1358 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1360 using namespace Menu_Helpers;
1362 void (Editor::*emf)(FadeShape);
1363 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1366 images = &_xfade_in_images;
1367 emf = &Editor::set_fade_in_shape;
1369 images = &_xfade_out_images;
1370 emf = &Editor::set_fade_out_shape;
1375 _("Linear (for highly correlated material)"),
1376 *(*images)[FadeLinear],
1377 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1381 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 _("Constant power"),
1386 *(*images)[FadeConstantPower],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *(*images)[FadeSymmetric],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 *(*images)[FadeSlow],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1409 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1414 *(*images)[FadeFast],
1415 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1418 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1421 /** Pop up a context menu for when the user clicks on a start crossfade */
1423 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1425 using namespace Menu_Helpers;
1427 MenuList& items (xfade_in_context_menu.items());
1429 if (items.empty()) {
1430 fill_xfade_menu (items, true);
1433 xfade_in_context_menu.popup (button, time);
1436 /** Pop up a context menu for when the user clicks on an end crossfade */
1438 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1440 using namespace Menu_Helpers;
1442 MenuList& items (xfade_out_context_menu.items());
1444 if (items.empty()) {
1445 fill_xfade_menu (items, false);
1448 xfade_out_context_menu.popup (button, time);
1452 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1454 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1456 using namespace Menu_Helpers;
1457 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1460 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1464 MenuList& items (fade_context_menu.items());
1467 switch (item_type) {
1469 case FadeInHandleItem:
1470 if (arv->audio_region()->fade_in_active()) {
1471 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1473 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1476 items.push_back (SeparatorElem());
1478 if (Profile->get_sae()) {
1480 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1481 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1488 *_fade_in_images[FadeLinear],
1489 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1493 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 *_fade_in_images[FadeSlow],
1499 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1502 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1507 *_fade_in_images[FadeFast],
1508 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1511 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1516 *_fade_in_images[FadeSymmetric],
1517 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1522 _("Constant power"),
1523 *_fade_in_images[FadeConstantPower],
1524 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1527 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1533 case FadeOutHandleItem:
1534 if (arv->audio_region()->fade_out_active()) {
1535 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1537 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1540 items.push_back (SeparatorElem());
1542 if (Profile->get_sae()) {
1543 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1544 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1550 *_fade_out_images[FadeLinear],
1551 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1555 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1560 *_fade_out_images[FadeSlow],
1561 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1564 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1569 *_fade_out_images[FadeFast],
1570 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1573 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1578 *_fade_out_images[FadeSymmetric],
1579 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1584 _("Constant power"),
1585 *_fade_out_images[FadeConstantPower],
1586 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1589 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1595 fatal << _("programming error: ")
1596 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1601 fade_context_menu.popup (button, time);
1605 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1607 using namespace Menu_Helpers;
1608 Menu* (Editor::*build_menu_function)();
1611 switch (item_type) {
1613 case RegionViewName:
1614 case RegionViewNameHighlight:
1615 case LeftFrameHandle:
1616 case RightFrameHandle:
1617 if (with_selection) {
1618 build_menu_function = &Editor::build_track_selection_context_menu;
1620 build_menu_function = &Editor::build_track_region_context_menu;
1625 if (with_selection) {
1626 build_menu_function = &Editor::build_track_selection_context_menu;
1628 build_menu_function = &Editor::build_track_context_menu;
1633 if (clicked_routeview->track()) {
1634 build_menu_function = &Editor::build_track_context_menu;
1636 build_menu_function = &Editor::build_track_bus_context_menu;
1641 /* probably shouldn't happen but if it does, we don't care */
1645 menu = (this->*build_menu_function)();
1646 menu->set_name ("ArdourContextMenu");
1648 /* now handle specific situations */
1650 switch (item_type) {
1652 case RegionViewName:
1653 case RegionViewNameHighlight:
1654 case LeftFrameHandle:
1655 case RightFrameHandle:
1656 if (!with_selection) {
1657 if (region_edit_menu_split_item) {
1658 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1659 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1661 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1664 if (region_edit_menu_split_multichannel_item) {
1665 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1666 region_edit_menu_split_multichannel_item->set_sensitive (true);
1668 region_edit_menu_split_multichannel_item->set_sensitive (false);
1681 /* probably shouldn't happen but if it does, we don't care */
1685 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1687 /* Bounce to disk */
1689 using namespace Menu_Helpers;
1690 MenuList& edit_items = menu->items();
1692 edit_items.push_back (SeparatorElem());
1694 switch (clicked_routeview->audio_track()->freeze_state()) {
1695 case AudioTrack::NoFreeze:
1696 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1699 case AudioTrack::Frozen:
1700 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1703 case AudioTrack::UnFrozen:
1704 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1710 if (item_type == StreamItem && clicked_routeview) {
1711 clicked_routeview->build_underlay_menu(menu);
1714 /* When the region menu is opened, we setup the actions so that they look right
1717 sensitize_the_right_region_actions ();
1718 _last_region_menu_was_main = false;
1720 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1721 menu->popup (button, time);
1725 Editor::build_track_context_menu ()
1727 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_context_menu.items();
1732 add_dstream_context_items (edit_items);
1733 return &track_context_menu;
1737 Editor::build_track_bus_context_menu ()
1739 using namespace Menu_Helpers;
1741 MenuList& edit_items = track_context_menu.items();
1744 add_bus_context_items (edit_items);
1745 return &track_context_menu;
1749 Editor::build_track_region_context_menu ()
1751 using namespace Menu_Helpers;
1752 MenuList& edit_items = track_region_context_menu.items();
1755 /* we've just cleared the track region context menu, so the menu that these
1756 two items were on will have disappeared; stop them dangling.
1758 region_edit_menu_split_item = 0;
1759 region_edit_menu_split_multichannel_item = 0;
1761 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1764 boost::shared_ptr<Track> tr;
1765 boost::shared_ptr<Playlist> pl;
1767 if ((tr = rtv->track())) {
1768 add_region_context_items (edit_items, tr);
1772 add_dstream_context_items (edit_items);
1774 return &track_region_context_menu;
1778 Editor::analyze_region_selection ()
1780 if (analysis_window == 0) {
1781 analysis_window = new AnalysisWindow();
1784 analysis_window->set_session(_session);
1786 analysis_window->show_all();
1789 analysis_window->set_regionmode();
1790 analysis_window->analyze();
1792 analysis_window->present();
1796 Editor::analyze_range_selection()
1798 if (analysis_window == 0) {
1799 analysis_window = new AnalysisWindow();
1802 analysis_window->set_session(_session);
1804 analysis_window->show_all();
1807 analysis_window->set_rangemode();
1808 analysis_window->analyze();
1810 analysis_window->present();
1814 Editor::build_track_selection_context_menu ()
1816 using namespace Menu_Helpers;
1817 MenuList& edit_items = track_selection_context_menu.items();
1818 edit_items.clear ();
1820 add_selection_context_items (edit_items);
1821 // edit_items.push_back (SeparatorElem());
1822 // add_dstream_context_items (edit_items);
1824 return &track_selection_context_menu;
1828 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1830 using namespace Menu_Helpers;
1832 /* OK, stick the region submenu at the top of the list, and then add
1836 RegionSelection rs = get_regions_from_selection_and_entered ();
1838 string::size_type pos = 0;
1839 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1841 /* we have to hack up the region name because "_" has a special
1842 meaning for menu titles.
1845 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1846 menu_item_name.replace (pos, 1, "__");
1850 if (_popup_region_menu_item == 0) {
1851 _popup_region_menu_item = new MenuItem (menu_item_name);
1852 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1853 _popup_region_menu_item->show ();
1855 _popup_region_menu_item->set_label (menu_item_name);
1858 const framepos_t position = get_preferred_edit_position (false, true);
1860 edit_items.push_back (*_popup_region_menu_item);
1861 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1862 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1864 edit_items.push_back (SeparatorElem());
1867 /** Add context menu items relevant to selection ranges.
1868 * @param edit_items List to add the items to.
1871 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1873 using namespace Menu_Helpers;
1875 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1876 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1878 edit_items.push_back (SeparatorElem());
1879 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1881 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (
1885 _("Move Range Start to Previous Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1890 edit_items.push_back (
1892 _("Move Range Start to Next Region Boundary"),
1893 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1897 edit_items.push_back (
1899 _("Move Range End to Previous Region Boundary"),
1900 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1904 edit_items.push_back (
1906 _("Move Range End to Next Region Boundary"),
1907 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1913 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1918 edit_items.push_back (SeparatorElem());
1919 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1920 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1925 edit_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1927 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1928 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1932 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1933 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1934 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1935 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1940 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1942 using namespace Menu_Helpers;
1946 Menu *play_menu = manage (new Menu);
1947 MenuList& play_items = play_menu->items();
1948 play_menu->set_name ("ArdourContextMenu");
1950 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1951 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1952 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1953 play_items.push_back (SeparatorElem());
1954 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1956 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1960 Menu *select_menu = manage (new Menu);
1961 MenuList& select_items = select_menu->items();
1962 select_menu->set_name ("ArdourContextMenu");
1964 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1965 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1966 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1967 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1968 select_items.push_back (SeparatorElem());
1969 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1970 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1971 select_items.push_back (SeparatorElem());
1972 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1973 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1974 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1975 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1976 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1977 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1978 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1980 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1984 Menu *cutnpaste_menu = manage (new Menu);
1985 MenuList& cutnpaste_items = cutnpaste_menu->items();
1986 cutnpaste_menu->set_name ("ArdourContextMenu");
1988 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1989 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1990 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1992 cutnpaste_items.push_back (SeparatorElem());
1994 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1995 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1997 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1999 /* Adding new material */
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2003 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2007 Menu *nudge_menu = manage (new Menu());
2008 MenuList& nudge_items = nudge_menu->items();
2009 nudge_menu->set_name ("ArdourContextMenu");
2011 edit_items.push_back (SeparatorElem());
2012 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2013 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2014 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2015 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2017 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2021 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2023 using namespace Menu_Helpers;
2027 Menu *play_menu = manage (new Menu);
2028 MenuList& play_items = play_menu->items();
2029 play_menu->set_name ("ArdourContextMenu");
2031 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2032 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2033 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2037 Menu *select_menu = manage (new Menu);
2038 MenuList& select_items = select_menu->items();
2039 select_menu->set_name ("ArdourContextMenu");
2041 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2042 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2044 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2045 select_items.push_back (SeparatorElem());
2046 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2047 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2048 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2049 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2051 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2055 Menu *cutnpaste_menu = manage (new Menu);
2056 MenuList& cutnpaste_items = cutnpaste_menu->items();
2057 cutnpaste_menu->set_name ("ArdourContextMenu");
2059 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2060 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2061 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2063 Menu *nudge_menu = manage (new Menu());
2064 MenuList& nudge_items = nudge_menu->items();
2065 nudge_menu->set_name ("ArdourContextMenu");
2067 edit_items.push_back (SeparatorElem());
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2071 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2073 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2077 Editor::snap_type() const
2083 Editor::snap_mode() const
2089 Editor::set_snap_to (SnapType st)
2091 unsigned int snap_ind = (unsigned int)st;
2095 if (snap_ind > snap_type_strings.size() - 1) {
2097 _snap_type = (SnapType)snap_ind;
2100 string str = snap_type_strings[snap_ind];
2102 if (str != snap_type_selector.get_active_text()) {
2103 snap_type_selector.set_active_text (str);
2108 switch (_snap_type) {
2109 case SnapToBeatDiv128:
2110 case SnapToBeatDiv64:
2111 case SnapToBeatDiv32:
2112 case SnapToBeatDiv28:
2113 case SnapToBeatDiv24:
2114 case SnapToBeatDiv20:
2115 case SnapToBeatDiv16:
2116 case SnapToBeatDiv14:
2117 case SnapToBeatDiv12:
2118 case SnapToBeatDiv10:
2119 case SnapToBeatDiv8:
2120 case SnapToBeatDiv7:
2121 case SnapToBeatDiv6:
2122 case SnapToBeatDiv5:
2123 case SnapToBeatDiv4:
2124 case SnapToBeatDiv3:
2125 case SnapToBeatDiv2: {
2126 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2127 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2129 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2130 current_bbt_points_begin, current_bbt_points_end);
2131 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2132 current_bbt_points_begin, current_bbt_points_end);
2133 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2137 case SnapToRegionStart:
2138 case SnapToRegionEnd:
2139 case SnapToRegionSync:
2140 case SnapToRegionBoundary:
2141 build_region_boundary_cache ();
2149 SnapChanged (); /* EMIT SIGNAL */
2153 Editor::set_snap_mode (SnapMode mode)
2155 string str = snap_mode_strings[(int)mode];
2157 if (_internal_editing) {
2158 internal_snap_mode = mode;
2160 pre_internal_snap_mode = mode;
2165 if (str != snap_mode_selector.get_active_text ()) {
2166 snap_mode_selector.set_active_text (str);
2172 Editor::set_edit_point_preference (EditPoint ep, bool force)
2174 bool changed = (_edit_point != ep);
2177 string str = edit_point_strings[(int)ep];
2179 if (str != edit_point_selector.get_active_text ()) {
2180 edit_point_selector.set_active_text (str);
2183 set_canvas_cursor ();
2185 if (!force && !changed) {
2189 const char* action=NULL;
2191 switch (_edit_point) {
2192 case EditAtPlayhead:
2193 action = "edit-at-playhead";
2195 case EditAtSelectedMarker:
2196 action = "edit-at-marker";
2199 action = "edit-at-mouse";
2203 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2205 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2209 bool in_track_canvas;
2211 if (!mouse_frame (foo, in_track_canvas)) {
2212 in_track_canvas = false;
2215 reset_canvas_action_sensitivity (in_track_canvas);
2221 Editor::set_state (const XMLNode& node, int /*version*/)
2223 const XMLProperty* prop;
2230 g.base_width = default_width;
2231 g.base_height = default_height;
2235 if ((geometry = find_named_node (node, "geometry")) != 0) {
2239 if ((prop = geometry->property("x_size")) == 0) {
2240 prop = geometry->property ("x-size");
2243 g.base_width = atoi(prop->value());
2245 if ((prop = geometry->property("y_size")) == 0) {
2246 prop = geometry->property ("y-size");
2249 g.base_height = atoi(prop->value());
2252 if ((prop = geometry->property ("x_pos")) == 0) {
2253 prop = geometry->property ("x-pos");
2256 x = atoi (prop->value());
2259 if ((prop = geometry->property ("y_pos")) == 0) {
2260 prop = geometry->property ("y-pos");
2263 y = atoi (prop->value());
2267 set_default_size (g.base_width, g.base_height);
2270 if (_session && (prop = node.property ("playhead"))) {
2272 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2273 playhead_cursor->set_position (pos);
2275 playhead_cursor->set_position (0);
2278 if ((prop = node.property ("mixer-width"))) {
2279 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2282 if ((prop = node.property ("zoom-focus"))) {
2283 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2286 if ((prop = node.property ("zoom"))) {
2287 reset_zoom (PBD::atof (prop->value()));
2289 reset_zoom (frames_per_pixel);
2292 if ((prop = node.property ("snap-to"))) {
2293 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2296 if ((prop = node.property ("snap-mode"))) {
2297 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2300 if ((prop = node.property ("internal-snap-to"))) {
2301 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2304 if ((prop = node.property ("internal-snap-mode"))) {
2305 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2308 if ((prop = node.property ("pre-internal-snap-to"))) {
2309 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2313 if ((prop = node.property ("pre-internal-snap-mode"))) {
2314 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2317 if ((prop = node.property ("mouse-mode"))) {
2318 MouseMode m = str2mousemode(prop->value());
2319 set_mouse_mode (m, true);
2321 set_mouse_mode (MouseObject, true);
2324 if ((prop = node.property ("left-frame")) != 0) {
2326 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2330 reset_x_origin (pos);
2334 if ((prop = node.property ("y-origin")) != 0) {
2335 reset_y_origin (atof (prop->value ()));
2338 if ((prop = node.property ("internal-edit"))) {
2339 bool yn = string_is_affirmative (prop->value());
2340 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2342 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2343 tact->set_active (!yn);
2344 tact->set_active (yn);
2348 if ((prop = node.property ("join-object-range"))) {
2349 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2350 bool yn = string_is_affirmative (prop->value());
2352 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2356 set_mouse_mode(mouse_mode, true);
2359 if ((prop = node.property ("edit-point"))) {
2360 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2363 if ((prop = node.property ("show-measures"))) {
2364 bool yn = string_is_affirmative (prop->value());
2365 _show_measures = yn;
2366 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2368 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2369 /* do it twice to force the change */
2370 tact->set_active (!yn);
2371 tact->set_active (yn);
2375 if ((prop = node.property ("follow-playhead"))) {
2376 bool yn = string_is_affirmative (prop->value());
2377 set_follow_playhead (yn);
2378 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2380 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2381 if (tact->get_active() != yn) {
2382 tact->set_active (yn);
2387 if ((prop = node.property ("stationary-playhead"))) {
2388 bool yn = string_is_affirmative (prop->value());
2389 set_stationary_playhead (yn);
2390 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2392 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2393 if (tact->get_active() != yn) {
2394 tact->set_active (yn);
2399 if ((prop = node.property ("region-list-sort-type"))) {
2400 RegionListSortType st;
2401 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2404 if ((prop = node.property ("show-editor-mixer"))) {
2406 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2409 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410 bool yn = string_is_affirmative (prop->value());
2412 /* do it twice to force the change */
2414 tact->set_active (!yn);
2415 tact->set_active (yn);
2418 if ((prop = node.property ("show-editor-list"))) {
2420 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2423 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2424 bool yn = string_is_affirmative (prop->value());
2426 /* do it twice to force the change */
2428 tact->set_active (!yn);
2429 tact->set_active (yn);
2432 if ((prop = node.property (X_("editor-list-page")))) {
2433 _the_notebook.set_current_page (atoi (prop->value ()));
2436 if ((prop = node.property (X_("show-marker-lines")))) {
2437 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2439 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2440 bool yn = string_is_affirmative (prop->value ());
2442 tact->set_active (!yn);
2443 tact->set_active (yn);
2446 XMLNodeList children = node.children ();
2447 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2448 selection->set_state (**i, Stateful::current_state_version);
2449 _regions->set_state (**i);
2452 if ((prop = node.property ("maximised"))) {
2453 bool yn = string_is_affirmative (prop->value());
2455 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2459 if ((prop = node.property ("nudge-clock-value"))) {
2461 sscanf (prop->value().c_str(), "%" PRId64, &f);
2462 nudge_clock->set (f);
2464 nudge_clock->set_mode (AudioClock::Timecode);
2465 nudge_clock->set (_session->frame_rate() * 5, true);
2472 Editor::get_state ()
2474 XMLNode* node = new XMLNode ("Editor");
2477 id().print (buf, sizeof (buf));
2478 node->add_property ("id", buf);
2480 if (is_realized()) {
2481 Glib::RefPtr<Gdk::Window> win = get_window();
2483 int x, y, width, height;
2484 win->get_root_origin(x, y);
2485 win->get_size(width, height);
2487 XMLNode* geometry = new XMLNode ("geometry");
2489 snprintf(buf, sizeof(buf), "%d", width);
2490 geometry->add_property("x-size", string(buf));
2491 snprintf(buf, sizeof(buf), "%d", height);
2492 geometry->add_property("y-size", string(buf));
2493 snprintf(buf, sizeof(buf), "%d", x);
2494 geometry->add_property("x-pos", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", y);
2496 geometry->add_property("y-pos", string(buf));
2497 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2498 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2499 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2500 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2501 geometry->add_property("edit-vertical-pane-pos", string(buf));
2503 node->add_child_nocopy (*geometry);
2506 maybe_add_mixer_strip_width (*node);
2508 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2509 snprintf (buf, sizeof(buf), "%f", frames_per_pixel);
2510 node->add_property ("zoom", buf);
2511 node->add_property ("snap-to", enum_2_string (_snap_type));
2512 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2513 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2514 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2515 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2516 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2517 node->add_property ("edit-point", enum_2_string (_edit_point));
2519 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2520 node->add_property ("playhead", buf);
2521 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2522 node->add_property ("left-frame", buf);
2523 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2524 node->add_property ("y-origin", buf);
2526 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2527 node->add_property ("maximised", _maximised ? "yes" : "no");
2528 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2529 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2530 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2531 node->add_property ("mouse-mode", enum2str(mouse_mode));
2532 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2533 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2535 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2537 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2538 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2541 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2543 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2544 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2547 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2548 node->add_property (X_("editor-list-page"), buf);
2550 if (button_bindings) {
2551 XMLNode* bb = new XMLNode (X_("Buttons"));
2552 button_bindings->save (*bb);
2553 node->add_child_nocopy (*bb);
2556 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2558 node->add_child_nocopy (selection->get_state ());
2559 node->add_child_nocopy (_regions->get_state ());
2561 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2562 node->add_property ("nudge-clock-value", buf);
2569 /** @param y y offset from the top of all trackviews.
2570 * @return pair: TimeAxisView that y is over, layer index.
2571 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2572 * in stacked or expanded region display mode, otherwise 0.
2574 std::pair<TimeAxisView *, double>
2575 Editor::trackview_by_y_position (double y)
2577 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2579 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2585 return std::make_pair ( (TimeAxisView *) 0, 0);
2588 /** Snap a position to the grid, if appropriate, taking into account current
2589 * grid settings and also the state of any snap modifier keys that may be pressed.
2590 * @param start Position to snap.
2591 * @param event Event to get current key modifier information from, or 0.
2594 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2596 if (!_session || !event) {
2600 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2601 if (_snap_mode == SnapOff) {
2602 snap_to_internal (start, direction, for_mark);
2605 if (_snap_mode != SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2612 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2614 if (!_session || _snap_mode == SnapOff) {
2618 snap_to_internal (start, direction, for_mark);
2622 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2624 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2625 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2627 switch (_snap_type) {
2628 case SnapToTimecodeFrame:
2629 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2630 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2632 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2636 case SnapToTimecodeSeconds:
2637 if (_session->config.get_timecode_offset_negative()) {
2638 start += _session->config.get_timecode_offset ();
2640 start -= _session->config.get_timecode_offset ();
2642 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2643 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2645 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2648 if (_session->config.get_timecode_offset_negative()) {
2649 start -= _session->config.get_timecode_offset ();
2651 start += _session->config.get_timecode_offset ();
2655 case SnapToTimecodeMinutes:
2656 if (_session->config.get_timecode_offset_negative()) {
2657 start += _session->config.get_timecode_offset ();
2659 start -= _session->config.get_timecode_offset ();
2661 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2662 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2664 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2666 if (_session->config.get_timecode_offset_negative()) {
2667 start -= _session->config.get_timecode_offset ();
2669 start += _session->config.get_timecode_offset ();
2673 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2679 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2681 const framepos_t one_second = _session->frame_rate();
2682 const framepos_t one_minute = _session->frame_rate() * 60;
2683 framepos_t presnap = start;
2687 switch (_snap_type) {
2688 case SnapToTimecodeFrame:
2689 case SnapToTimecodeSeconds:
2690 case SnapToTimecodeMinutes:
2691 return timecode_snap_to_internal (start, direction, for_mark);
2694 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2695 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2697 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2702 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2703 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2705 start = (framepos_t) floor ((double) start / one_second) * one_second;
2710 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2711 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2713 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2718 start = _session->tempo_map().round_to_bar (start, direction);
2722 start = _session->tempo_map().round_to_beat (start, direction);
2725 case SnapToBeatDiv128:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2728 case SnapToBeatDiv64:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2731 case SnapToBeatDiv32:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2734 case SnapToBeatDiv28:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2737 case SnapToBeatDiv24:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2740 case SnapToBeatDiv20:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2743 case SnapToBeatDiv16:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2746 case SnapToBeatDiv14:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2749 case SnapToBeatDiv12:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2752 case SnapToBeatDiv10:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2755 case SnapToBeatDiv8:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2758 case SnapToBeatDiv7:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2761 case SnapToBeatDiv6:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2764 case SnapToBeatDiv5:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2767 case SnapToBeatDiv4:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2770 case SnapToBeatDiv3:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2773 case SnapToBeatDiv2:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2782 _session->locations()->marks_either_side (start, before, after);
2784 if (before == max_framepos && after == max_framepos) {
2785 /* No marks to snap to, so just don't snap */
2787 } else if (before == max_framepos) {
2789 } else if (after == max_framepos) {
2791 } else if (before != max_framepos && after != max_framepos) {
2792 /* have before and after */
2793 if ((start - before) < (after - start)) {
2802 case SnapToRegionStart:
2803 case SnapToRegionEnd:
2804 case SnapToRegionSync:
2805 case SnapToRegionBoundary:
2806 if (!region_boundary_cache.empty()) {
2808 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2809 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2811 if (direction > 0) {
2812 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2814 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2817 if (next != region_boundary_cache.begin ()) {
2822 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2823 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2825 if (start > (p + n) / 2) {
2834 switch (_snap_mode) {
2840 if (presnap > start) {
2841 if (presnap > (start + unit_to_frame(snap_threshold))) {
2845 } else if (presnap < start) {
2846 if (presnap < (start - unit_to_frame(snap_threshold))) {
2852 /* handled at entry */
2860 Editor::setup_toolbar ()
2862 HBox* mode_box = manage(new HBox);
2863 mode_box->set_border_width (2);
2864 mode_box->set_spacing(4);
2866 HBox* mouse_mode_box = manage (new HBox);
2867 HBox* mouse_mode_hbox = manage (new HBox);
2868 VBox* mouse_mode_vbox = manage (new VBox);
2869 Alignment* mouse_mode_align = manage (new Alignment);
2871 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2872 // mouse_mode_size_group->add_widget (smart_mode_button);
2873 mouse_mode_size_group->add_widget (mouse_move_button);
2874 mouse_mode_size_group->add_widget (mouse_select_button);
2875 mouse_mode_size_group->add_widget (mouse_zoom_button);
2876 mouse_mode_size_group->add_widget (mouse_gain_button);
2877 mouse_mode_size_group->add_widget (mouse_timefx_button);
2878 mouse_mode_size_group->add_widget (mouse_audition_button);
2879 mouse_mode_size_group->add_widget (mouse_draw_button);
2880 mouse_mode_size_group->add_widget (internal_edit_button);
2882 /* make them just a bit bigger */
2883 mouse_move_button.set_size_request (-1, 30);
2885 mouse_mode_hbox->set_spacing (2);
2887 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2895 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2897 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2899 mouse_mode_align->add (*mouse_mode_vbox);
2900 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2902 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2904 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2905 if (!Profile->get_sae()) {
2906 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2908 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2910 edit_mode_selector.set_name ("EditModeSelector");
2911 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2912 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2914 mode_box->pack_start (edit_mode_selector, false, false);
2915 mode_box->pack_start (*mouse_mode_box, false, false);
2917 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2918 _mouse_mode_tearoff->set_name ("MouseModeBase");
2919 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2921 if (Profile->get_sae()) {
2922 _mouse_mode_tearoff->set_can_be_torn_off (false);
2925 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2926 &_mouse_mode_tearoff->tearoff_window()));
2927 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2928 &_mouse_mode_tearoff->tearoff_window(), 1));
2929 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window()));
2931 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932 &_mouse_mode_tearoff->tearoff_window(), 1));
2936 _zoom_box.set_spacing (2);
2937 _zoom_box.set_border_width (2);
2941 zoom_in_button.set_name ("zoom button");
2942 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2943 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2944 zoom_in_button.set_image(::get_icon ("zoom_in"));
2945 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2946 zoom_in_button.set_related_action (act);
2948 zoom_out_button.set_name ("zoom button");
2949 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2950 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2951 zoom_out_button.set_image(::get_icon ("zoom_out"));
2952 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2953 zoom_out_button.set_related_action (act);
2955 zoom_out_full_button.set_name ("zoom button");
2956 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2957 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2958 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2959 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2960 zoom_out_full_button.set_related_action (act);
2962 zoom_focus_selector.set_name ("ZoomFocusSelector");
2963 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2964 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2966 _zoom_box.pack_start (zoom_out_button, false, false);
2967 _zoom_box.pack_start (zoom_in_button, false, false);
2968 _zoom_box.pack_start (zoom_out_full_button, false, false);
2970 _zoom_box.pack_start (zoom_focus_selector, false, false);
2972 /* Track zoom buttons */
2973 tav_expand_button.set_name ("zoom button");
2974 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2975 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2976 tav_expand_button.set_size_request (-1, 20);
2977 tav_expand_button.set_image(::get_icon ("tav_exp"));
2978 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2979 tav_expand_button.set_related_action (act);
2981 tav_shrink_button.set_name ("zoom button");
2982 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2983 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2984 tav_shrink_button.set_size_request (-1, 20);
2985 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2986 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2987 tav_shrink_button.set_related_action (act);
2989 _zoom_box.pack_start (tav_shrink_button);
2990 _zoom_box.pack_start (tav_expand_button);
2992 _zoom_tearoff = manage (new TearOff (_zoom_box));
2994 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2995 &_zoom_tearoff->tearoff_window()));
2996 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2997 &_zoom_tearoff->tearoff_window(), 0));
2998 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2999 &_zoom_tearoff->tearoff_window()));
3000 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3001 &_zoom_tearoff->tearoff_window(), 0));
3003 snap_box.set_spacing (2);
3004 snap_box.set_border_width (2);
3006 snap_type_selector.set_name ("SnapTypeSelector");
3007 set_popdown_strings (snap_type_selector, snap_type_strings);
3008 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3010 snap_mode_selector.set_name ("SnapModeSelector");
3011 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3012 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3014 edit_point_selector.set_name ("EditPointSelector");
3015 set_popdown_strings (edit_point_selector, edit_point_strings);
3016 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3018 snap_box.pack_start (snap_mode_selector, false, false);
3019 snap_box.pack_start (snap_type_selector, false, false);
3020 snap_box.pack_start (edit_point_selector, false, false);
3024 HBox *nudge_box = manage (new HBox);
3025 nudge_box->set_spacing (2);
3026 nudge_box->set_border_width (2);
3028 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3029 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3031 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3032 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3034 nudge_box->pack_start (nudge_backward_button, false, false);
3035 nudge_box->pack_start (nudge_forward_button, false, false);
3036 nudge_box->pack_start (*nudge_clock, false, false);
3039 /* Pack everything in... */
3041 HBox* hbox = manage (new HBox);
3042 hbox->set_spacing(10);
3044 _tools_tearoff = manage (new TearOff (*hbox));
3045 _tools_tearoff->set_name ("MouseModeBase");
3046 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3048 if (Profile->get_sae()) {
3049 _tools_tearoff->set_can_be_torn_off (false);
3052 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3053 &_tools_tearoff->tearoff_window()));
3054 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3055 &_tools_tearoff->tearoff_window(), 0));
3056 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window()));
3058 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window(), 0));
3061 toolbar_hbox.set_spacing (10);
3062 toolbar_hbox.set_border_width (1);
3064 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3065 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3066 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3068 hbox->pack_start (snap_box, false, false);
3069 if (!Profile->get_small_screen()) {
3070 hbox->pack_start (*nudge_box, false, false);
3072 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3074 hbox->pack_start (panic_box, false, false);
3078 toolbar_base.set_name ("ToolBarBase");
3079 toolbar_base.add (toolbar_hbox);
3081 _toolbar_viewport.add (toolbar_base);
3082 /* stick to the required height but allow width to vary if there's not enough room */
3083 _toolbar_viewport.set_size_request (1, -1);
3085 toolbar_frame.set_shadow_type (SHADOW_OUT);
3086 toolbar_frame.set_name ("BaseFrame");
3087 toolbar_frame.add (_toolbar_viewport);
3091 Editor::setup_tooltips ()
3093 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3094 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3095 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3096 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3097 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3098 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3099 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3100 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3101 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3102 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3103 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3104 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3105 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3106 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3107 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3108 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3109 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3110 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3111 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3112 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3113 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3114 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3115 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3119 Editor::convert_drop_to_paths (
3120 vector<string>& paths,
3121 const RefPtr<Gdk::DragContext>& /*context*/,
3124 const SelectionData& data,
3128 if (_session == 0) {
3132 vector<string> uris = data.get_uris();
3136 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3137 are actually URI lists. So do it by hand.
3140 if (data.get_target() != "text/plain") {
3144 /* Parse the "uri-list" format that Nautilus provides,
3145 where each pathname is delimited by \r\n.
3147 THERE MAY BE NO NULL TERMINATING CHAR!!!
3150 string txt = data.get_text();
3154 p = (const char *) malloc (txt.length() + 1);
3155 txt.copy (const_cast<char *> (p), txt.length(), 0);
3156 const_cast<char*>(p)[txt.length()] = '\0';
3162 while (g_ascii_isspace (*p))
3166 while (*q && (*q != '\n') && (*q != '\r')) {
3173 while (q > p && g_ascii_isspace (*q))
3178 uris.push_back (string (p, q - p + 1));
3182 p = strchr (p, '\n');
3194 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3196 if ((*i).substr (0,7) == "file://") {
3198 string const p = PBD::url_decode (*i);
3200 // scan forward past three slashes
3202 string::size_type slashcnt = 0;
3203 string::size_type n = 0;
3204 string::const_iterator x = p.begin();
3206 while (slashcnt < 3 && x != p.end()) {
3209 } else if (slashcnt == 3) {
3216 if (slashcnt != 3 || x == p.end()) {
3217 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3221 paths.push_back (p.substr (n - 1));
3229 Editor::new_tempo_section ()
3235 Editor::map_transport_state ()
3237 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3239 if (_session && _session->transport_stopped()) {
3240 have_pending_keyboard_selection = false;
3243 update_loop_range_view (true);
3249 Editor::begin_reversible_command (string name)
3252 _session->begin_reversible_command (name);
3257 Editor::begin_reversible_command (GQuark q)
3260 _session->begin_reversible_command (q);
3265 Editor::commit_reversible_command ()
3268 _session->commit_reversible_command ();
3273 Editor::history_changed ()
3277 if (undo_action && _session) {
3278 if (_session->undo_depth() == 0) {
3279 label = S_("Command|Undo");
3281 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3283 undo_action->property_label() = label;
3286 if (redo_action && _session) {
3287 if (_session->redo_depth() == 0) {
3290 label = string_compose(_("Redo (%1)"), _session->next_redo());
3292 redo_action->property_label() = label;
3297 Editor::duplicate_range (bool with_dialog)
3301 RegionSelection rs = get_regions_from_selection_and_entered ();
3303 if ( selection->time.length() == 0 && rs.empty()) {
3309 ArdourDialog win (_("Duplicate"));
3310 Label label (_("Number of duplications:"));
3311 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3312 SpinButton spinner (adjustment, 0.0, 1);
3315 win.get_vbox()->set_spacing (12);
3316 win.get_vbox()->pack_start (hbox);
3317 hbox.set_border_width (6);
3318 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3320 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3321 place, visually. so do this by hand.
3324 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3325 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3326 spinner.grab_focus();
3332 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3333 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3334 win.set_default_response (RESPONSE_ACCEPT);
3336 win.set_position (WIN_POS_MOUSE);
3338 spinner.grab_focus ();
3340 switch (win.run ()) {
3341 case RESPONSE_ACCEPT:
3347 times = adjustment.get_value();
3350 if ((current_mouse_mode() == Editing::MouseRange)) {
3351 if (selection->time.length()) {
3352 duplicate_selection (times);
3354 } else if (get_smart_mode()) {
3355 if (selection->time.length()) {
3356 duplicate_selection (times);
3358 duplicate_some_regions (rs, times);
3360 duplicate_some_regions (rs, times);
3365 Editor::set_edit_mode (EditMode m)
3367 Config->set_edit_mode (m);
3371 Editor::cycle_edit_mode ()
3373 switch (Config->get_edit_mode()) {
3375 if (Profile->get_sae()) {
3376 Config->set_edit_mode (Lock);
3378 Config->set_edit_mode (Splice);
3382 Config->set_edit_mode (Lock);
3385 Config->set_edit_mode (Slide);
3391 Editor::edit_mode_selection_done ()
3393 string s = edit_mode_selector.get_active_text ();
3396 Config->set_edit_mode (string_to_edit_mode (s));
3401 Editor::snap_type_selection_done ()
3403 string choice = snap_type_selector.get_active_text();
3404 SnapType snaptype = SnapToBeat;
3406 if (choice == _("Beats/2")) {
3407 snaptype = SnapToBeatDiv2;
3408 } else if (choice == _("Beats/3")) {
3409 snaptype = SnapToBeatDiv3;
3410 } else if (choice == _("Beats/4")) {
3411 snaptype = SnapToBeatDiv4;
3412 } else if (choice == _("Beats/5")) {
3413 snaptype = SnapToBeatDiv5;
3414 } else if (choice == _("Beats/6")) {
3415 snaptype = SnapToBeatDiv6;
3416 } else if (choice == _("Beats/7")) {
3417 snaptype = SnapToBeatDiv7;
3418 } else if (choice == _("Beats/8")) {
3419 snaptype = SnapToBeatDiv8;
3420 } else if (choice == _("Beats/10")) {
3421 snaptype = SnapToBeatDiv10;
3422 } else if (choice == _("Beats/12")) {
3423 snaptype = SnapToBeatDiv12;
3424 } else if (choice == _("Beats/14")) {
3425 snaptype = SnapToBeatDiv14;
3426 } else if (choice == _("Beats/16")) {
3427 snaptype = SnapToBeatDiv16;
3428 } else if (choice == _("Beats/20")) {
3429 snaptype = SnapToBeatDiv20;
3430 } else if (choice == _("Beats/24")) {
3431 snaptype = SnapToBeatDiv24;
3432 } else if (choice == _("Beats/28")) {
3433 snaptype = SnapToBeatDiv28;
3434 } else if (choice == _("Beats/32")) {
3435 snaptype = SnapToBeatDiv32;
3436 } else if (choice == _("Beats/64")) {
3437 snaptype = SnapToBeatDiv64;
3438 } else if (choice == _("Beats/128")) {
3439 snaptype = SnapToBeatDiv128;
3440 } else if (choice == _("Beats")) {
3441 snaptype = SnapToBeat;
3442 } else if (choice == _("Bars")) {
3443 snaptype = SnapToBar;
3444 } else if (choice == _("Marks")) {
3445 snaptype = SnapToMark;
3446 } else if (choice == _("Region starts")) {
3447 snaptype = SnapToRegionStart;
3448 } else if (choice == _("Region ends")) {
3449 snaptype = SnapToRegionEnd;
3450 } else if (choice == _("Region bounds")) {
3451 snaptype = SnapToRegionBoundary;
3452 } else if (choice == _("Region syncs")) {
3453 snaptype = SnapToRegionSync;
3454 } else if (choice == _("CD Frames")) {
3455 snaptype = SnapToCDFrame;
3456 } else if (choice == _("Timecode Frames")) {
3457 snaptype = SnapToTimecodeFrame;
3458 } else if (choice == _("Timecode Seconds")) {
3459 snaptype = SnapToTimecodeSeconds;
3460 } else if (choice == _("Timecode Minutes")) {
3461 snaptype = SnapToTimecodeMinutes;
3462 } else if (choice == _("Seconds")) {
3463 snaptype = SnapToSeconds;
3464 } else if (choice == _("Minutes")) {
3465 snaptype = SnapToMinutes;
3468 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3470 ract->set_active ();
3475 Editor::snap_mode_selection_done ()
3477 string choice = snap_mode_selector.get_active_text();
3478 SnapMode mode = SnapNormal;
3480 if (choice == _("No Grid")) {
3482 } else if (choice == _("Grid")) {
3484 } else if (choice == _("Magnetic")) {
3485 mode = SnapMagnetic;
3488 RefPtr<RadioAction> ract = snap_mode_action (mode);
3491 ract->set_active (true);
3496 Editor::cycle_edit_point (bool with_marker)
3498 switch (_edit_point) {
3500 set_edit_point_preference (EditAtPlayhead);
3502 case EditAtPlayhead:
3504 set_edit_point_preference (EditAtSelectedMarker);
3506 set_edit_point_preference (EditAtMouse);
3509 case EditAtSelectedMarker:
3510 set_edit_point_preference (EditAtMouse);
3516 Editor::edit_point_selection_done ()
3518 string choice = edit_point_selector.get_active_text();
3519 EditPoint ep = EditAtSelectedMarker;
3521 if (choice == _("Marker")) {
3522 set_edit_point_preference (EditAtSelectedMarker);
3523 } else if (choice == _("Playhead")) {
3524 set_edit_point_preference (EditAtPlayhead);
3526 set_edit_point_preference (EditAtMouse);
3529 RefPtr<RadioAction> ract = edit_point_action (ep);
3532 ract->set_active (true);
3537 Editor::zoom_focus_selection_done ()
3539 string choice = zoom_focus_selector.get_active_text();
3540 ZoomFocus focus_type = ZoomFocusLeft;
3542 if (choice == _("Left")) {
3543 focus_type = ZoomFocusLeft;
3544 } else if (choice == _("Right")) {
3545 focus_type = ZoomFocusRight;
3546 } else if (choice == _("Center")) {
3547 focus_type = ZoomFocusCenter;
3548 } else if (choice == _("Playhead")) {
3549 focus_type = ZoomFocusPlayhead;
3550 } else if (choice == _("Mouse")) {
3551 focus_type = ZoomFocusMouse;
3552 } else if (choice == _("Edit point")) {
3553 focus_type = ZoomFocusEdit;
3556 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3559 ract->set_active ();
3564 Editor::edit_controls_button_release (GdkEventButton* ev)
3566 if (Keyboard::is_context_menu_event (ev)) {
3567 ARDOUR_UI::instance()->add_route (this);
3568 } else if (ev->button == 1) {
3569 selection->clear_tracks ();
3576 Editor::mouse_select_button_release (GdkEventButton* ev)
3578 /* this handles just right-clicks */
3580 if (ev->button != 3) {
3588 Editor::set_zoom_focus (ZoomFocus f)
3590 string str = zoom_focus_strings[(int)f];
3592 if (str != zoom_focus_selector.get_active_text()) {
3593 zoom_focus_selector.set_active_text (str);
3596 if (zoom_focus != f) {
3603 Editor::cycle_zoom_focus ()
3605 switch (zoom_focus) {
3607 set_zoom_focus (ZoomFocusRight);
3609 case ZoomFocusRight:
3610 set_zoom_focus (ZoomFocusCenter);
3612 case ZoomFocusCenter:
3613 set_zoom_focus (ZoomFocusPlayhead);
3615 case ZoomFocusPlayhead:
3616 set_zoom_focus (ZoomFocusMouse);
3618 case ZoomFocusMouse:
3619 set_zoom_focus (ZoomFocusEdit);
3622 set_zoom_focus (ZoomFocusLeft);
3628 Editor::ensure_float (Window& win)
3630 win.set_transient_for (*this);
3634 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3636 /* recover or initialize pane positions. do this here rather than earlier because
3637 we don't want the positions to change the child allocations, which they seem to do.
3643 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3652 XMLNode* geometry = find_named_node (*node, "geometry");
3654 if (which == static_cast<Paned*> (&edit_pane)) {
3656 if (done & Horizontal) {
3660 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3661 _notebook_shrunk = string_is_affirmative (prop->value ());
3664 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3665 /* initial allocation is 90% to canvas, 10% to notebook */
3666 pos = (int) floor (alloc.get_width() * 0.90f);
3667 snprintf (buf, sizeof(buf), "%d", pos);
3669 pos = atoi (prop->value());
3672 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3673 edit_pane.set_position (pos);
3676 done = (Pane) (done | Horizontal);
3678 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3680 if (done & Vertical) {
3684 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3685 /* initial allocation is 90% to canvas, 10% to summary */
3686 pos = (int) floor (alloc.get_height() * 0.90f);
3687 snprintf (buf, sizeof(buf), "%d", pos);
3690 pos = atoi (prop->value());
3693 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3694 editor_summary_pane.set_position (pos);
3697 done = (Pane) (done | Vertical);
3702 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3704 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3705 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3706 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3707 top_hbox.remove (toolbar_frame);
3712 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3714 if (toolbar_frame.get_parent() == 0) {
3715 top_hbox.pack_end (toolbar_frame);
3720 Editor::set_show_measures (bool yn)
3722 if (_show_measures != yn) {
3725 if ((_show_measures = yn) == true) {
3727 tempo_lines->show();
3729 (void) redraw_measures ();
3736 Editor::toggle_follow_playhead ()
3738 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3740 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3741 set_follow_playhead (tact->get_active());
3745 /** @param yn true to follow playhead, otherwise false.
3746 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3749 Editor::set_follow_playhead (bool yn, bool catch_up)
3751 if (_follow_playhead != yn) {
3752 if ((_follow_playhead = yn) == true && catch_up) {
3754 reset_x_origin_to_follow_playhead ();
3761 Editor::toggle_stationary_playhead ()
3763 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3765 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3766 set_stationary_playhead (tact->get_active());
3771 Editor::set_stationary_playhead (bool yn)
3773 if (_stationary_playhead != yn) {
3774 if ((_stationary_playhead = yn) == true) {
3776 // FIXME need a 3.0 equivalent of this 2.X call
3777 // update_current_screen ();
3784 Editor::playlist_selector () const
3786 return *_playlist_selector;
3790 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3794 switch (_snap_type) {
3799 case SnapToBeatDiv128:
3802 case SnapToBeatDiv64:
3805 case SnapToBeatDiv32:
3808 case SnapToBeatDiv28:
3811 case SnapToBeatDiv24:
3814 case SnapToBeatDiv20:
3817 case SnapToBeatDiv16:
3820 case SnapToBeatDiv14:
3823 case SnapToBeatDiv12:
3826 case SnapToBeatDiv10:
3829 case SnapToBeatDiv8:
3832 case SnapToBeatDiv7:
3835 case SnapToBeatDiv6:
3838 case SnapToBeatDiv5:
3841 case SnapToBeatDiv4:
3844 case SnapToBeatDiv3:
3847 case SnapToBeatDiv2:
3853 return _session->tempo_map().meter_at (position).divisions_per_bar();
3858 case SnapToTimecodeFrame:
3859 case SnapToTimecodeSeconds:
3860 case SnapToTimecodeMinutes:
3863 case SnapToRegionStart:
3864 case SnapToRegionEnd:
3865 case SnapToRegionSync:
3866 case SnapToRegionBoundary:
3876 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3880 ret = nudge_clock->current_duration (pos);
3881 next = ret + 1; /* XXXX fix me */
3887 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3889 ArdourDialog dialog (_("Playlist Deletion"));
3890 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3891 "If it is kept, its audio files will not be cleaned.\n"
3892 "If it is deleted, audio files used by it alone will be cleaned."),
3895 dialog.set_position (WIN_POS_CENTER);
3896 dialog.get_vbox()->pack_start (label);
3900 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3901 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3902 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3904 switch (dialog.run ()) {
3905 case RESPONSE_ACCEPT:
3906 /* delete the playlist */
3910 case RESPONSE_REJECT:
3911 /* keep the playlist */
3923 Editor::audio_region_selection_covers (framepos_t where)
3925 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3926 if ((*a)->region()->covers (where)) {
3935 Editor::prepare_for_cleanup ()
3937 cut_buffer->clear_regions ();
3938 cut_buffer->clear_playlists ();
3940 selection->clear_regions ();
3941 selection->clear_playlists ();
3943 _regions->suspend_redisplay ();
3947 Editor::finish_cleanup ()
3949 _regions->resume_redisplay ();
3953 Editor::transport_loop_location()
3956 return _session->locations()->auto_loop_location();
3963 Editor::transport_punch_location()
3966 return _session->locations()->auto_punch_location();
3973 Editor::control_layout_scroll (GdkEventScroll* ev)
3975 if (Keyboard::some_magic_widget_has_focus()) {
3979 switch (ev->direction) {
3981 scroll_tracks_up_line ();
3985 case GDK_SCROLL_DOWN:
3986 scroll_tracks_down_line ();
3990 /* no left/right handling yet */
3998 Editor::session_state_saved (string)
4001 _snapshots->redisplay ();
4005 Editor::update_tearoff_visibility()
4007 bool visible = Config->get_keep_tearoffs();
4008 _mouse_mode_tearoff->set_visible (visible);
4009 _tools_tearoff->set_visible (visible);
4010 _zoom_tearoff->set_visible (visible);
4014 Editor::maximise_editing_space ()
4026 Editor::restore_editing_space ()
4038 * Make new playlists for a given track and also any others that belong
4039 * to the same active route group with the `select' property.
4044 Editor::new_playlists (TimeAxisView* v)
4046 begin_reversible_command (_("new playlists"));
4047 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4048 _session->playlists->get (playlists);
4049 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4050 commit_reversible_command ();
4054 * Use a copy of the current playlist for a given track and also any others that belong
4055 * to the same active route group with the `select' property.
4060 Editor::copy_playlists (TimeAxisView* v)
4062 begin_reversible_command (_("copy playlists"));
4063 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4064 _session->playlists->get (playlists);
4065 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4066 commit_reversible_command ();
4069 /** Clear the current playlist for a given track and also any others that belong
4070 * to the same active route group with the `select' property.
4075 Editor::clear_playlists (TimeAxisView* v)
4077 begin_reversible_command (_("clear playlists"));
4078 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4079 _session->playlists->get (playlists);
4080 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4081 commit_reversible_command ();
4085 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4087 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4091 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4093 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4097 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4099 atv.clear_playlist ();
4103 Editor::on_key_press_event (GdkEventKey* ev)
4105 return key_press_focus_accelerator_handler (*this, ev);
4109 Editor::on_key_release_event (GdkEventKey* ev)
4111 return Gtk::Window::on_key_release_event (ev);
4112 // return key_press_focus_accelerator_handler (*this, ev);
4115 /** Queue up a change to the viewport x origin.
4116 * @param frame New x origin.
4119 Editor::reset_x_origin (framepos_t frame)
4121 pending_visual_change.add (VisualChange::TimeOrigin);
4122 pending_visual_change.time_origin = frame;
4123 ensure_visual_change_idle_handler ();
4127 Editor::reset_y_origin (double y)
4129 pending_visual_change.add (VisualChange::YOrigin);
4130 pending_visual_change.y_origin = y;
4131 ensure_visual_change_idle_handler ();
4135 Editor::reset_zoom (double fpp)
4137 clamp_frames_per_pixel (fpp);
4139 if (fpp == frames_per_pixel) {
4143 pending_visual_change.add (VisualChange::ZoomLevel);
4144 pending_visual_change.frames_per_pixel = fpp;
4145 ensure_visual_change_idle_handler ();
4149 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4151 reset_x_origin (frame);
4154 if (!no_save_visual) {
4155 undo_visual_stack.push_back (current_visual_state(false));
4159 Editor::VisualState::VisualState (bool with_tracks)
4160 : gui_state (with_tracks ? new GUIObjectState : 0)
4164 Editor::VisualState::~VisualState ()
4169 Editor::VisualState*
4170 Editor::current_visual_state (bool with_tracks)
4172 VisualState* vs = new VisualState (with_tracks);
4173 vs->y_position = vertical_adjustment.get_value();
4174 vs->frames_per_pixel = frames_per_pixel;
4175 vs->leftmost_frame = leftmost_frame;
4176 vs->zoom_focus = zoom_focus;
4179 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4186 Editor::undo_visual_state ()
4188 if (undo_visual_stack.empty()) {
4192 VisualState* vs = undo_visual_stack.back();
4193 undo_visual_stack.pop_back();
4196 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4198 use_visual_state (*vs);
4202 Editor::redo_visual_state ()
4204 if (redo_visual_stack.empty()) {
4208 VisualState* vs = redo_visual_stack.back();
4209 redo_visual_stack.pop_back();
4211 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4213 use_visual_state (*vs);
4217 Editor::swap_visual_state ()
4219 if (undo_visual_stack.empty()) {
4220 redo_visual_state ();
4222 undo_visual_state ();
4227 Editor::use_visual_state (VisualState& vs)
4229 PBD::Unwinder<bool> nsv (no_save_visual, true);
4231 _routes->suspend_redisplay ();
4233 vertical_adjustment.set_value (vs.y_position);
4235 set_zoom_focus (vs.zoom_focus);
4236 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_pixel);
4239 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4241 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4242 (*i)->reset_visual_state ();
4246 _routes->update_visibility ();
4247 _routes->resume_redisplay ();
4250 /** This is the core function that controls the zoom level of the canvas. It is called
4251 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4252 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4255 Editor::set_frames_per_pixel (double fpp)
4258 tempo_lines->tempo_map_changed();
4261 frames_per_pixel = fpp;
4263 /* convert fpu to frame count */
4265 framepos_t frames = (framepos_t) floor (frames_per_pixel * _visible_canvas_width);
4267 if (frames_per_pixel != zoom_range_clock->current_duration()) {
4268 zoom_range_clock->set (frames);
4271 bool const showing_time_selection = selection->time.length() > 0;
4273 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4274 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4275 (*i)->reshow_selection (selection->time);
4279 ZoomChanged (); /* EMIT_SIGNAL */
4281 //reset_scrolling_region ();
4283 if (playhead_cursor) {
4284 playhead_cursor->set_position (playhead_cursor->current_frame ());
4287 refresh_location_display();
4288 _summary->set_overlays_dirty ();
4290 update_marker_labels ();
4296 Editor::queue_visual_videotimeline_update ()
4299 * pending_visual_change.add (VisualChange::VideoTimeline);
4300 * or maybe even more specific: which videotimeline-image
4301 * currently it calls update_video_timeline() to update
4302 * _all outdated_ images on the video-timeline.
4303 * see 'exposeimg()' in video_image_frame.cc
4305 ensure_visual_change_idle_handler ();
4309 Editor::ensure_visual_change_idle_handler ()
4311 if (pending_visual_change.idle_handler_id < 0) {
4312 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4313 pending_visual_change.being_handled = false;
4318 Editor::_idle_visual_changer (void* arg)
4320 return static_cast<Editor*>(arg)->idle_visual_changer ();
4324 Editor::idle_visual_changer ()
4326 /* set_horizontal_position() below (and maybe other calls) call
4327 gtk_main_iteration(), so it's possible that a signal will be handled
4328 half-way through this method. If this signal wants an
4329 idle_visual_changer we must schedule another one after this one, so
4330 mark the idle_handler_id as -1 here to allow that. Also make a note
4331 that we are doing the visual change, so that changes in response to
4332 super-rapid-screen-update can be dropped if we are still processing
4336 pending_visual_change.idle_handler_id = -1;
4337 pending_visual_change.being_handled = true;
4339 VisualChange::Type p = pending_visual_change.pending;
4340 pending_visual_change.pending = (VisualChange::Type) 0;
4342 double const last_time_origin = horizontal_position ();
4344 if (p & VisualChange::ZoomLevel) {
4345 set_frames_per_pixel (pending_visual_change.frames_per_pixel);
4347 compute_fixed_ruler_scale ();
4349 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4350 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4352 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4353 current_bbt_points_begin, current_bbt_points_end);
4354 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4355 current_bbt_points_begin, current_bbt_points_end);
4356 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4359 if (p & VisualChange::ZoomLevel) {
4360 update_video_timeline();
4363 if (p & VisualChange::TimeOrigin) {
4364 set_horizontal_position (pending_visual_change.time_origin / frames_per_pixel);
4367 if (p & VisualChange::YOrigin) {
4368 vertical_adjustment.set_value (pending_visual_change.y_origin);
4371 if (last_time_origin == horizontal_position ()) {
4372 /* changed signal not emitted */
4373 update_fixed_rulers ();
4374 redisplay_tempo (true);
4377 if (!(p & VisualChange::ZoomLevel)) {
4378 update_video_timeline();
4381 _summary->set_overlays_dirty ();
4383 pending_visual_change.being_handled = false;
4384 return 0; /* this is always a one-shot call */
4387 struct EditorOrderTimeAxisSorter {
4388 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4389 return a->order () < b->order ();
4394 Editor::sort_track_selection (TrackViewList& sel)
4396 EditorOrderTimeAxisSorter cmp;
4401 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4404 framepos_t where = 0;
4405 EditPoint ep = _edit_point;
4407 if (from_context_menu && (ep == EditAtMouse)) {
4408 return event_frame (&context_click_event, 0, 0);
4411 if (entered_marker) {
4412 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4413 return entered_marker->position();
4416 if (ignore_playhead && ep == EditAtPlayhead) {
4417 ep = EditAtSelectedMarker;
4421 case EditAtPlayhead:
4422 where = _session->audible_frame();
4423 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4426 case EditAtSelectedMarker:
4427 if (!selection->markers.empty()) {
4429 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4432 where = loc->start();
4436 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4444 if (!mouse_frame (where, ignored)) {
4445 /* XXX not right but what can we do ? */
4449 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4457 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4459 if (!_session) return;
4461 begin_reversible_command (cmd);
4465 if ((tll = transport_loop_location()) == 0) {
4466 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4467 XMLNode &before = _session->locations()->get_state();
4468 _session->locations()->add (loc, true);
4469 _session->set_auto_loop_location (loc);
4470 XMLNode &after = _session->locations()->get_state();
4471 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4473 XMLNode &before = tll->get_state();
4474 tll->set_hidden (false, this);
4475 tll->set (start, end);
4476 XMLNode &after = tll->get_state();
4477 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4480 commit_reversible_command ();
4484 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4486 if (!_session) return;
4488 begin_reversible_command (cmd);
4492 if ((tpl = transport_punch_location()) == 0) {
4493 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4494 XMLNode &before = _session->locations()->get_state();
4495 _session->locations()->add (loc, true);
4496 _session->set_auto_loop_location (loc);
4497 XMLNode &after = _session->locations()->get_state();
4498 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4501 XMLNode &before = tpl->get_state();
4502 tpl->set_hidden (false, this);
4503 tpl->set (start, end);
4504 XMLNode &after = tpl->get_state();
4505 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4508 commit_reversible_command ();
4511 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4512 * @param rs List to which found regions are added.
4513 * @param where Time to look at.
4514 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4517 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4519 const TrackViewList* tracks;
4522 tracks = &track_views;
4527 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4529 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4532 boost::shared_ptr<Track> tr;
4533 boost::shared_ptr<Playlist> pl;
4535 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4537 boost::shared_ptr<RegionList> regions = pl->regions_at (
4538 (framepos_t) floor ( (double) where * tr->speed()));
4540 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4541 RegionView* rv = rtv->view()->find_view (*i);
4552 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4554 const TrackViewList* tracks;
4557 tracks = &track_views;
4562 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4563 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4565 boost::shared_ptr<Track> tr;
4566 boost::shared_ptr<Playlist> pl;
4568 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4570 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4571 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4573 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4575 RegionView* rv = rtv->view()->find_view (*i);
4586 /** Get regions using the following method:
4588 * Make a region list using the selected regions, unless
4589 * the edit point is `mouse' and the mouse is over an unselected
4590 * region. In this case, use just that region.
4592 * If the edit point is not 'mouse', and there are no regions selected,
4593 * search the list of selected tracks and return regions that are under
4594 * the edit point on these tracks. If there are no selected tracks and
4595 * 'No Selection = All Tracks' is active, search all tracks,
4597 * The rationale here is that the mouse edit point is special in that
4598 * its position describes both a time and a track; the other edit
4599 * modes only describe a time. Hence if the edit point is `mouse' we
4600 * ignore selected tracks, as we assume the user means something by
4601 * pointing at a particular track. Also in this case we take note of
4602 * the region directly under the edit point, as there is always just one
4603 * (rather than possibly several with non-mouse edit points).
4607 Editor::get_regions_from_selection_and_edit_point ()
4609 RegionSelection regions;
4611 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4612 regions.add (entered_regionview);
4614 regions = selection->regions;
4618 if (regions.empty() && _edit_point != EditAtMouse) {
4619 TrackViewList tracks = selection->tracks;
4621 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4622 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4623 * is enabled, so consider all tracks
4625 tracks = track_views;
4628 if (!tracks.empty()) {
4629 /* no region selected or entered, but some selected tracks:
4630 * act on all regions on the selected tracks at the edit point
4632 framepos_t const where = get_preferred_edit_position ();
4633 get_regions_at(regions, where, tracks);
4639 /** Start with regions that are selected, or the entered regionview if none are selected.
4640 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4641 * of the regions that we started with.
4645 Editor::get_regions_from_selection_and_entered ()
4647 RegionSelection regions = selection->regions;
4649 if (regions.empty() && entered_regionview) {
4650 regions.add (entered_regionview);
4657 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4659 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4661 RouteTimeAxisView* tatv;
4663 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4665 boost::shared_ptr<Playlist> pl;
4666 vector<boost::shared_ptr<Region> > results;
4668 boost::shared_ptr<Track> tr;
4670 if ((tr = tatv->track()) == 0) {
4675 if ((pl = (tr->playlist())) != 0) {
4676 if (src_comparison) {
4677 pl->get_source_equivalent_regions (region, results);
4679 pl->get_region_list_equivalent_regions (region, results);
4683 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4684 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4685 regions.push_back (marv);
4694 Editor::show_rhythm_ferret ()
4696 if (rhythm_ferret == 0) {
4697 rhythm_ferret = new RhythmFerret(*this);
4700 rhythm_ferret->set_session (_session);
4701 rhythm_ferret->show ();
4702 rhythm_ferret->present ();
4706 Editor::first_idle ()
4708 MessageDialog* dialog = 0;
4710 if (track_views.size() > 1) {
4711 dialog = new MessageDialog (
4713 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4717 ARDOUR_UI::instance()->flush_pending ();
4720 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4724 // first idle adds route children (automation tracks), so we need to redisplay here
4725 _routes->redisplay ();
4732 Editor::_idle_resize (gpointer arg)
4734 return ((Editor*)arg)->idle_resize ();
4738 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4740 if (resize_idle_id < 0) {
4741 resize_idle_id = g_idle_add (_idle_resize, this);
4742 _pending_resize_amount = 0;
4745 /* make a note of the smallest resulting height, so that we can clamp the
4746 lower limit at TimeAxisView::hSmall */
4748 int32_t min_resulting = INT32_MAX;
4750 _pending_resize_amount += h;
4751 _pending_resize_view = view;
4753 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4755 if (selection->tracks.contains (_pending_resize_view)) {
4756 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4757 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4761 if (min_resulting < 0) {
4766 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4767 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4771 /** Handle pending resizing of tracks */
4773 Editor::idle_resize ()
4775 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4777 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4778 selection->tracks.contains (_pending_resize_view)) {
4780 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4781 if (*i != _pending_resize_view) {
4782 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4787 _pending_resize_amount = 0;
4789 _group_tabs->set_dirty ();
4790 resize_idle_id = -1;
4798 ENSURE_GUI_THREAD (*this, &Editor::located);
4801 playhead_cursor->set_position (_session->audible_frame ());
4802 if (_follow_playhead && !_pending_initial_locate) {
4803 reset_x_origin_to_follow_playhead ();
4807 _pending_locate_request = false;
4808 _pending_initial_locate = false;
4812 Editor::region_view_added (RegionView *)
4814 _summary->set_dirty ();
4818 Editor::region_view_removed ()
4820 _summary->set_dirty ();
4824 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4826 TrackViewList::const_iterator j = track_views.begin ();
4827 while (j != track_views.end()) {
4828 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4829 if (rtv && rtv->route() == r) {
4840 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4844 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4845 TimeAxisView* tv = axis_view_from_route (*i);
4855 Editor::add_routes (RouteList& routes)
4857 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4859 RouteTimeAxisView *rtv;
4860 list<RouteTimeAxisView*> new_views;
4862 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4863 boost::shared_ptr<Route> route = (*x);
4865 if (route->is_auditioner() || route->is_monitor()) {
4869 DataType dt = route->input()->default_type();
4871 if (dt == ARDOUR::DataType::AUDIO) {
4872 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4873 rtv->set_route (route);
4874 } else if (dt == ARDOUR::DataType::MIDI) {
4875 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4876 rtv->set_route (route);
4878 throw unknown_type();
4881 new_views.push_back (rtv);
4882 track_views.push_back (rtv);
4884 rtv->effective_gain_display ();
4886 if (internal_editing()) {
4887 rtv->enter_internal_edit_mode ();
4889 rtv->leave_internal_edit_mode ();
4892 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4893 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4896 _routes->routes_added (new_views);
4897 _summary->routes_added (new_views);
4899 if (show_editor_mixer_when_tracks_arrive) {
4900 show_editor_mixer (true);
4903 editor_list_button.set_sensitive (true);
4907 Editor::timeaxisview_deleted (TimeAxisView *tv)
4909 if (_session && _session->deletion_in_progress()) {
4910 /* the situation is under control */
4914 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4916 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4918 _routes->route_removed (tv);
4920 if (tv == entered_track) {
4924 TimeAxisView::Children c = tv->get_child_list ();
4925 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4926 if (entered_track == i->get()) {
4931 /* remove it from the list of track views */
4933 TrackViewList::iterator i;
4935 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4936 i = track_views.erase (i);
4939 /* update whatever the current mixer strip is displaying, if revelant */
4941 boost::shared_ptr<Route> route;
4944 route = rtav->route ();
4947 if (current_mixer_strip && current_mixer_strip->route() == route) {
4949 TimeAxisView* next_tv;
4951 if (track_views.empty()) {
4953 } else if (i == track_views.end()) {
4954 next_tv = track_views.front();
4961 set_selected_mixer_strip (*next_tv);
4963 /* make the editor mixer strip go away setting the
4964 * button to inactive (which also unticks the menu option)
4967 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4973 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4975 if (apply_to_selection) {
4976 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4978 TrackSelection::iterator j = i;
4981 hide_track_in_display (*i, false);
4986 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4988 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4989 // this will hide the mixer strip
4990 set_selected_mixer_strip (*tv);
4993 _routes->hide_track_in_display (*tv);
4998 Editor::sync_track_view_list_and_routes ()
5000 track_views = TrackViewList (_routes->views ());
5002 _summary->set_dirty ();
5003 _group_tabs->set_dirty ();
5005 return false; // do not call again (until needed)
5009 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5011 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5016 /** Find a RouteTimeAxisView by the ID of its route */
5018 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5020 RouteTimeAxisView* v;
5022 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5024 if(v->route()->id() == id) {
5034 Editor::fit_route_group (RouteGroup *g)
5036 TrackViewList ts = axis_views_from_routes (g->route_list ());
5041 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5043 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5046 _session->cancel_audition ();
5050 if (_session->is_auditioning()) {
5051 _session->cancel_audition ();
5052 if (r == last_audition_region) {
5057 _session->audition_region (r);
5058 last_audition_region = r;
5063 Editor::hide_a_region (boost::shared_ptr<Region> r)
5065 r->set_hidden (true);
5069 Editor::show_a_region (boost::shared_ptr<Region> r)
5071 r->set_hidden (false);
5075 Editor::audition_region_from_region_list ()
5077 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5081 Editor::hide_region_from_region_list ()
5083 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5087 Editor::show_region_in_region_list ()
5089 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5093 Editor::step_edit_status_change (bool yn)
5096 start_step_editing ();
5098 stop_step_editing ();
5103 Editor::start_step_editing ()
5105 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5109 Editor::stop_step_editing ()
5111 step_edit_connection.disconnect ();
5115 Editor::check_step_edit ()
5117 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5118 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5120 mtv->check_step_edit ();
5124 return true; // do it again, till we stop
5128 Editor::scroll_press (Direction dir)
5130 ++_scroll_callbacks;
5132 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5133 /* delay the first auto-repeat */
5139 scroll_backward (1);
5147 scroll_tracks_up_line ();
5151 scroll_tracks_down_line ();
5155 /* do hacky auto-repeat */
5156 if (!_scroll_connection.connected ()) {
5158 _scroll_connection = Glib::signal_timeout().connect (
5159 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5162 _scroll_callbacks = 0;
5169 Editor::scroll_release ()
5171 _scroll_connection.disconnect ();
5174 /** Queue a change for the Editor viewport x origin to follow the playhead */
5176 Editor::reset_x_origin_to_follow_playhead ()
5178 framepos_t const frame = playhead_cursor->current_frame ();
5180 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5182 if (_session->transport_speed() < 0) {
5184 if (frame > (current_page_frames() / 2)) {
5185 center_screen (frame-(current_page_frames()/2));
5187 center_screen (current_page_frames()/2);
5194 if (frame < leftmost_frame) {
5196 if (_session->transport_rolling()) {
5197 /* rolling; end up with the playhead at the right of the page */
5198 l = frame - current_page_frames ();
5200 /* not rolling: end up with the playhead 1/4 of the way along the page */
5201 l = frame - current_page_frames() / 4;
5205 if (_session->transport_rolling()) {
5206 /* rolling: end up with the playhead on the left of the page */
5209 /* not rolling: end up with the playhead 3/4 of the way along the page */
5210 l = frame - 3 * current_page_frames() / 4;
5218 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5224 Editor::super_rapid_screen_update ()
5226 if (!_session || !_session->engine().running()) {
5230 /* METERING / MIXER STRIPS */
5232 /* update track meters, if required */
5233 if (is_mapped() && meters_running) {
5234 RouteTimeAxisView* rtv;
5235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5236 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5237 rtv->fast_update ();
5242 /* and any current mixer strip */
5243 if (current_mixer_strip) {
5244 current_mixer_strip->fast_update ();
5247 /* PLAYHEAD AND VIEWPORT */
5249 framepos_t const frame = _session->audible_frame();
5251 /* There are a few reasons why we might not update the playhead / viewport stuff:
5253 * 1. we don't update things when there's a pending locate request, otherwise
5254 * when the editor requests a locate there is a chance that this method
5255 * will move the playhead before the locate request is processed, causing
5257 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5258 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5261 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5263 last_update_frame = frame;
5265 if (!_dragging_playhead) {
5266 playhead_cursor->set_position (frame);
5269 if (!_stationary_playhead) {
5271 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5272 /* We only do this if we aren't already
5273 handling a visual change (ie if
5274 pending_visual_change.being_handled is
5275 false) so that these requests don't stack
5276 up there are too many of them to handle in
5279 reset_x_origin_to_follow_playhead ();
5284 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5288 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5289 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_pixel;
5290 if (target <= 0.0) {
5293 if (fabs(target - current) < current_page_frames() / frames_per_pixel) {
5294 target = (target * 0.15) + (current * 0.85);
5300 set_horizontal_position (current);
5309 Editor::session_going_away ()
5311 _have_idled = false;
5313 _session_connections.drop_connections ();
5315 super_rapid_screen_update_connection.disconnect ();
5317 selection->clear ();
5318 cut_buffer->clear ();
5320 clicked_regionview = 0;
5321 clicked_axisview = 0;
5322 clicked_routeview = 0;
5323 entered_regionview = 0;
5325 last_update_frame = 0;
5328 playhead_cursor->hide ();
5330 /* rip everything out of the list displays */
5334 _route_groups->clear ();
5336 /* do this first so that deleting a track doesn't reset cms to null
5337 and thus cause a leak.
5340 if (current_mixer_strip) {
5341 if (current_mixer_strip->get_parent() != 0) {
5342 global_hpacker.remove (*current_mixer_strip);
5344 delete current_mixer_strip;
5345 current_mixer_strip = 0;
5348 /* delete all trackviews */
5350 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5353 track_views.clear ();
5355 zoom_range_clock->set_session (0);
5356 nudge_clock->set_session (0);
5358 editor_list_button.set_active(false);
5359 editor_list_button.set_sensitive(false);
5361 /* clear tempo/meter rulers */
5362 remove_metric_marks ();
5364 clear_marker_display ();
5366 stop_step_editing ();
5368 /* get rid of any existing editor mixer strip */
5370 WindowTitle title(Glib::get_application_name());
5371 title += _("Editor");
5373 set_title (title.get_string());
5375 SessionHandlePtr::session_going_away ();
5380 Editor::show_editor_list (bool yn)
5383 _the_notebook.show ();
5385 _the_notebook.hide ();
5390 Editor::change_region_layering_order (bool from_context_menu)
5392 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5394 if (!clicked_routeview) {
5395 if (layering_order_editor) {
5396 layering_order_editor->hide ();
5401 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5407 boost::shared_ptr<Playlist> pl = track->playlist();
5413 if (layering_order_editor == 0) {
5414 layering_order_editor = new RegionLayeringOrderEditor (*this);
5415 layering_order_editor->set_position (WIN_POS_MOUSE);
5418 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5419 layering_order_editor->maybe_present ();
5423 Editor::update_region_layering_order_editor ()
5425 if (layering_order_editor && layering_order_editor->is_visible ()) {
5426 change_region_layering_order (true);
5431 Editor::setup_fade_images ()
5433 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5434 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5435 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5436 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5437 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5439 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5440 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5441 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5442 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5443 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5445 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5446 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5447 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5448 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5449 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5451 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5452 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5453 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5454 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5455 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5459 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5461 Editor::action_menu_item (std::string const & name)
5463 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5466 return *manage (a->create_menu_item ());
5470 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5472 EventBox* b = manage (new EventBox);
5473 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5474 Label* l = manage (new Label (name));
5478 _the_notebook.append_page (widget, *b);
5482 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5484 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5485 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5488 if (ev->type == GDK_2BUTTON_PRESS) {
5490 /* double-click on a notebook tab shrinks or expands the notebook */
5492 if (_notebook_shrunk) {
5493 if (pre_notebook_shrink_pane_width) {
5494 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5496 _notebook_shrunk = false;
5498 pre_notebook_shrink_pane_width = edit_pane.get_position();
5500 /* this expands the LHS of the edit pane to cover the notebook
5501 PAGE but leaves the tabs visible.
5503 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5504 _notebook_shrunk = true;
5512 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5514 using namespace Menu_Helpers;
5516 MenuList& items = _control_point_context_menu.items ();
5519 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5520 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5521 if (!can_remove_control_point (item)) {
5522 items.back().set_sensitive (false);
5525 _control_point_context_menu.popup (event->button.button, event->button.time);
5529 Editor::shift_key_released ()
5531 _stepping_axis_view = 0;
5536 Editor::save_canvas_state ()
5538 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5539 string path = string_compose ("%1/canvas-state.xml", _session->path());