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 <glibmm/uriutils.h>
51 #include <gtkmm/image.h>
52 #include <gdkmm/color.h>
53 #include <gdkmm/bitmap.h>
55 #include <gtkmm/menu.h>
56 #include <gtkmm/menuitem.h>
58 #include "gtkmm2ext/bindings.h"
59 #include "gtkmm2ext/grouped_buttons.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/tearoff.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/location.h"
71 #include "ardour/profile.h"
72 #include "ardour/route_group.h"
73 #include "ardour/session_playlists.h"
74 #include "ardour/tempo.h"
75 #include "ardour/utils.h"
77 #include "canvas/debug.h"
78 #include "canvas/text.h"
80 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_time_axis.h"
110 #include "mixer_strip.h"
111 #include "mixer_ui.h"
112 #include "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "tempo_lines.h"
121 #include "time_axis_view.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)
257 , horizontal_adjustment (0.0, 0.0, 1e16)
258 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
260 , controls_layout (unused_adjustment, vertical_adjustment)
262 /* tool bar related */
264 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
265 , toolbar_selection_clock_table (2,3)
266 , _mouse_mode_tearoff (0)
267 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
275 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
276 , meters_running(false)
277 , _pending_locate_request (false)
278 , _pending_initial_locate (false)
279 , _last_cut_copy_source_track (0)
281 , _region_selection_change_updates_region_list (true)
282 , _following_mixer_selection (false)
283 , _control_point_toggled_on_press (false)
284 , _stepping_axis_view (0)
288 /* we are a singleton */
290 PublicEditor::_instance = this;
294 selection = new Selection (this);
295 cut_buffer = new Selection (this);
297 clicked_regionview = 0;
298 clicked_axisview = 0;
299 clicked_routeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 build_edit_mode_menu();
317 build_zoom_focus_menu();
318 build_track_count_menu();
319 build_snap_mode_menu();
320 build_snap_type_menu();
321 build_edit_point_menu();
323 snap_threshold = 5.0;
324 bbt_beat_subdivision = 4;
325 _visible_canvas_width = 0;
326 _visible_canvas_height = 0;
327 autoscroll_horizontal_allowed = false;
328 autoscroll_vertical_allowed = false;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
377 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
378 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
379 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
380 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
382 zoom_focus = ZoomFocusLeft;
383 _edit_point = EditAtMouse;
384 _internal_editing = false;
385 current_canvas_cursor = 0;
386 _visible_track_count = 16;
388 samples_per_pixel = 2048; /* too early to use reset_zoom () */
390 _scroll_callbacks = 0;
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorRulerLabel");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorRulerLabel");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorRulerLabel");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorRulerLabel");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorRulerLabel");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorRulerLabel");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 if (Profile->get_trx()) {
434 mark_label.set_text (_("Markers"));
436 mark_label.set_name ("EditorRulerLabel");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
441 mark_label.set_no_show_all();
443 cd_mark_label.set_name ("EditorRulerLabel");
444 cd_mark_label.set_size_request (-1, (int)timebar_height);
445 cd_mark_label.set_alignment (1.0, 0.5);
446 cd_mark_label.set_padding (5,0);
447 cd_mark_label.hide();
448 cd_mark_label.set_no_show_all();
450 videotl_bar_height = 4;
451 videotl_label.set_name ("EditorRulerLabel");
452 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
453 videotl_label.set_alignment (1.0, 0.5);
454 videotl_label.set_padding (5,0);
455 videotl_label.hide();
456 videotl_label.set_no_show_all();
458 range_mark_label.set_name ("EditorRulerLabel");
459 range_mark_label.set_size_request (-1, (int)timebar_height);
460 range_mark_label.set_alignment (1.0, 0.5);
461 range_mark_label.set_padding (5,0);
462 range_mark_label.hide();
463 range_mark_label.set_no_show_all();
465 transport_mark_label.set_name ("EditorRulerLabel");
466 transport_mark_label.set_size_request (-1, (int)timebar_height);
467 transport_mark_label.set_alignment (1.0, 0.5);
468 transport_mark_label.set_padding (5,0);
469 transport_mark_label.hide();
470 transport_mark_label.set_no_show_all();
472 initialize_canvas ();
473 initialize_rulers ();
475 _summary = new EditorSummary (this);
477 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
478 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
480 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
482 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
483 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
485 edit_controls_vbox.set_spacing (0);
486 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
487 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
489 HBox* h = manage (new HBox);
490 _group_tabs = new EditorGroupTabs (this);
491 if (!ARDOUR::Profile->get_trx()) {
492 h->pack_start (*_group_tabs, PACK_SHRINK);
494 h->pack_start (edit_controls_vbox);
495 controls_layout.add (*h);
497 controls_layout.set_name ("EditControlsBase");
498 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
499 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
500 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
502 _cursors = new MouseCursors;
503 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
505 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
507 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
508 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
509 pad_line_1->set_outline_color (0xFF0000FF);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 time_bars_event_box.add (time_bars_vbox);
522 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
523 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
525 /* labels for the time bars */
526 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
528 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
530 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
532 bottom_hbox.set_border_width (2);
533 bottom_hbox.set_spacing (3);
535 _route_groups = new EditorRouteGroups (this);
536 _routes = new EditorRoutes (this);
537 _regions = new EditorRegions (this);
538 _snapshots = new EditorSnapshots (this);
539 _locations = new EditorLocations (this);
541 add_notebook_page (_("Regions"), _regions->widget ());
542 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
543 add_notebook_page (_("Snapshots"), _snapshots->widget ());
544 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
545 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
547 _the_notebook.set_show_tabs (true);
548 _the_notebook.set_scrollable (true);
549 _the_notebook.popup_disable ();
550 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
551 _the_notebook.show_all ();
553 _notebook_shrunk = false;
555 editor_summary_pane.pack1(edit_packer);
557 Button* summary_arrows_left_left = manage (new Button);
558 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
559 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
560 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
562 Button* summary_arrows_left_right = manage (new Button);
563 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
564 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
565 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 VBox* summary_arrows_left = manage (new VBox);
568 summary_arrows_left->pack_start (*summary_arrows_left_left);
569 summary_arrows_left->pack_start (*summary_arrows_left_right);
571 Button* summary_arrows_right_up = manage (new Button);
572 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
573 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
574 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 Button* summary_arrows_right_down = manage (new Button);
577 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
578 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
579 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 VBox* summary_arrows_right = manage (new VBox);
582 summary_arrows_right->pack_start (*summary_arrows_right_up);
583 summary_arrows_right->pack_start (*summary_arrows_right_down);
585 Frame* summary_frame = manage (new Frame);
586 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
588 summary_frame->add (*_summary);
589 summary_frame->show ();
591 _summary_hbox.pack_start (*summary_arrows_left, false, false);
592 _summary_hbox.pack_start (*summary_frame, true, true);
593 _summary_hbox.pack_start (*summary_arrows_right, false, false);
595 if (!ARDOUR::Profile->get_trx()) {
596 editor_summary_pane.pack2 (_summary_hbox);
599 edit_pane.pack1 (editor_summary_pane, true, true);
600 if (!ARDOUR::Profile->get_trx()) {
601 edit_pane.pack2 (_the_notebook, false, true);
604 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
606 /* XXX: editor_summary_pane might need similar to the edit_pane */
608 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
610 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
611 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
613 top_hbox.pack_start (toolbar_frame);
615 HBox *hbox = manage (new HBox);
616 hbox->pack_start (edit_pane, true, true);
618 global_vpacker.pack_start (top_hbox, false, false);
619 global_vpacker.pack_start (*hbox, true, true);
621 global_hpacker.pack_start (global_vpacker, true, true);
623 set_name ("EditorWindow");
624 add_accel_group (ActionManager::ui_manager->get_accel_group());
626 status_bar_hpacker.show ();
628 vpacker.pack_end (status_bar_hpacker, false, false);
629 vpacker.pack_end (global_hpacker, true, true);
631 /* register actions now so that set_state() can find them and set toggles/checks etc */
634 /* when we start using our own keybinding system for the editor, this
635 * will be uncommented
641 set_zoom_focus (zoom_focus);
642 set_visible_track_count (_visible_track_count);
643 _snap_type = SnapToBeat;
644 set_snap_to (_snap_type);
645 _snap_mode = SnapOff;
646 set_snap_mode (_snap_mode);
647 set_mouse_mode (MouseObject, true);
648 pre_internal_mouse_mode = MouseObject;
649 pre_internal_snap_type = _snap_type;
650 pre_internal_snap_mode = _snap_mode;
651 internal_snap_type = _snap_type;
652 internal_snap_mode = _snap_mode;
653 set_edit_point_preference (EditAtMouse, true);
655 _playlist_selector = new PlaylistSelector();
656 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
658 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
662 nudge_forward_button.set_name ("nudge button");
663 // nudge_forward_button.add_elements (ArdourButton::Inset);
664 nudge_forward_button.set_image(::get_icon("nudge_right"));
666 nudge_backward_button.set_name ("nudge button");
667 // nudge_backward_button.add_elements (ArdourButton::Inset);
668 nudge_backward_button.set_image(::get_icon("nudge_left"));
670 fade_context_menu.set_name ("ArdourContextMenu");
672 /* icons, titles, WM stuff */
674 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
675 Glib::RefPtr<Gdk::Pixbuf> icon;
677 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
684 window_icons.push_back (icon);
686 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
687 window_icons.push_back (icon);
689 if (!window_icons.empty()) {
690 // set_icon_list (window_icons);
691 set_default_icon_list (window_icons);
694 WindowTitle title(Glib::get_application_name());
695 title += _("Editor");
696 set_title (title.get_string());
697 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
700 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
702 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
703 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
705 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
707 /* allow external control surfaces/protocols to do various things */
709 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
710 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
711 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
712 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
713 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
714 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
715 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
716 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
717 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
718 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
719 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
720 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
721 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
722 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
724 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
725 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
726 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
727 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
728 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
730 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
732 /* problematic: has to return a value and thus cannot be x-thread */
734 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
736 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
737 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
739 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
741 _ignore_region_action = false;
742 _last_region_menu_was_main = false;
743 _popup_region_menu_item = 0;
745 _show_marker_lines = false;
746 _over_region_trim_target = false;
748 /* Button bindings */
750 button_bindings = new Bindings;
752 XMLNode* node = button_settings();
754 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
755 button_bindings->load (**i);
762 setup_fade_images ();
767 delete button_bindings;
769 delete _route_groups;
770 delete _track_canvas_viewport;
775 Editor::button_settings () const
777 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
778 XMLNode* node = find_named_node (*settings, X_("Buttons"));
781 node = new XMLNode (X_("Buttons"));
788 Editor::add_toplevel_controls (Container& cont)
790 vpacker.pack_start (cont, false, false);
795 Editor::get_smart_mode () const
797 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
801 Editor::catch_vanishing_regionview (RegionView *rv)
803 /* note: the selection will take care of the vanishing
804 audioregionview by itself.
807 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
811 if (clicked_regionview == rv) {
812 clicked_regionview = 0;
815 if (entered_regionview == rv) {
816 set_entered_regionview (0);
819 if (!_all_region_actions_sensitized) {
820 sensitize_all_region_actions (true);
823 _over_region_trim_target = false;
827 Editor::set_entered_regionview (RegionView* rv)
829 if (rv == entered_regionview) {
833 if (entered_regionview) {
834 entered_regionview->exited ();
837 if ((entered_regionview = rv) != 0) {
838 entered_regionview->entered (internal_editing ());
841 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
842 /* This RegionView entry might have changed what region actions
843 are allowed, so sensitize them all in case a key is pressed.
845 sensitize_all_region_actions (true);
850 Editor::set_entered_track (TimeAxisView* tav)
853 entered_track->exited ();
856 if ((entered_track = tav) != 0) {
857 entered_track->entered ();
862 Editor::show_window ()
864 if (!is_visible ()) {
867 /* XXX: this is a bit unfortunate; it would probably
868 be nicer if we could just call show () above rather
869 than needing the show_all ()
872 /* re-hide stuff if necessary */
873 editor_list_button_toggled ();
874 parameter_changed ("show-summary");
875 parameter_changed ("show-group-tabs");
876 parameter_changed ("show-zoom-tools");
878 /* now reset all audio_time_axis heights, because widgets might need
884 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
885 tv = (static_cast<TimeAxisView*>(*i));
889 if (current_mixer_strip) {
890 current_mixer_strip->hide_things ();
891 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
899 Editor::instant_save ()
901 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
906 _session->add_instant_xml(get_state());
908 Config->add_instant_xml(get_state());
913 Editor::zoom_adjustment_changed ()
919 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
920 bool clamped = clamp_samples_per_pixel (fpu);
923 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
930 Editor::control_vertical_zoom_in_all ()
932 tav_zoom_smooth (false, true);
936 Editor::control_vertical_zoom_out_all ()
938 tav_zoom_smooth (true, true);
942 Editor::control_vertical_zoom_in_selected ()
944 tav_zoom_smooth (false, false);
948 Editor::control_vertical_zoom_out_selected ()
950 tav_zoom_smooth (true, false);
954 Editor::control_view (uint32_t view)
956 goto_visual_state (view);
960 Editor::control_unselect ()
962 selection->clear_tracks ();
966 Editor::control_select (uint32_t rid, Selection::Operation op)
968 /* handles the (static) signal from the ControlProtocol class that
969 * requests setting the selected track to a given RID
976 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
982 TimeAxisView* tav = axis_view_from_route (r);
987 selection->add (tav);
989 case Selection::Toggle:
990 selection->toggle (tav);
992 case Selection::Extend:
995 selection->set (tav);
999 selection->clear_tracks ();
1004 Editor::control_step_tracks_up ()
1006 scroll_tracks_up_line ();
1010 Editor::control_step_tracks_down ()
1012 scroll_tracks_down_line ();
1016 Editor::control_scroll (float fraction)
1018 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1024 double step = fraction * current_page_samples();
1027 _control_scroll_target is an optional<T>
1029 it acts like a pointer to an framepos_t, with
1030 a operator conversion to boolean to check
1031 that it has a value could possibly use
1032 playhead_cursor->current_frame to store the
1033 value and a boolean in the class to know
1034 when it's out of date
1037 if (!_control_scroll_target) {
1038 _control_scroll_target = _session->transport_frame();
1039 _dragging_playhead = true;
1042 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1043 *_control_scroll_target = 0;
1044 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1045 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1047 *_control_scroll_target += (framepos_t) floor (step);
1050 /* move visuals, we'll catch up with it later */
1052 playhead_cursor->set_position (*_control_scroll_target);
1053 UpdateAllTransportClocks (*_control_scroll_target);
1055 if (*_control_scroll_target > (current_page_samples() / 2)) {
1056 /* try to center PH in window */
1057 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1063 Now we do a timeout to actually bring the session to the right place
1064 according to the playhead. This is to avoid reading disk buffers on every
1065 call to control_scroll, which is driven by ScrollTimeline and therefore
1066 probably by a control surface wheel which can generate lots of events.
1068 /* cancel the existing timeout */
1070 control_scroll_connection.disconnect ();
1072 /* add the next timeout */
1074 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1078 Editor::deferred_control_scroll (framepos_t /*target*/)
1080 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1081 // reset for next stream
1082 _control_scroll_target = boost::none;
1083 _dragging_playhead = false;
1088 Editor::access_action (std::string action_group, std::string action_item)
1094 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1097 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1105 Editor::on_realize ()
1107 Window::on_realize ();
1112 Editor::map_position_change (framepos_t frame)
1114 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1116 if (_session == 0) {
1120 if (_follow_playhead) {
1121 center_screen (frame);
1124 playhead_cursor->set_position (frame);
1128 Editor::center_screen (framepos_t frame)
1130 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1132 /* if we're off the page, then scroll.
1135 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1136 center_screen_internal (frame, page);
1141 Editor::center_screen_internal (framepos_t frame, float page)
1146 frame -= (framepos_t) page;
1151 reset_x_origin (frame);
1156 Editor::update_title ()
1158 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1161 bool dirty = _session->dirty();
1163 string session_name;
1165 if (_session->snap_name() != _session->name()) {
1166 session_name = _session->snap_name();
1168 session_name = _session->name();
1172 session_name = "*" + session_name;
1175 WindowTitle title(session_name);
1176 title += Glib::get_application_name();
1177 set_title (title.get_string());
1179 /* ::session_going_away() will have taken care of it */
1184 Editor::set_session (Session *t)
1186 SessionHandlePtr::set_session (t);
1192 zoom_range_clock->set_session (_session);
1193 _playlist_selector->set_session (_session);
1194 nudge_clock->set_session (_session);
1195 _summary->set_session (_session);
1196 _group_tabs->set_session (_session);
1197 _route_groups->set_session (_session);
1198 _regions->set_session (_session);
1199 _snapshots->set_session (_session);
1200 _routes->set_session (_session);
1201 _locations->set_session (_session);
1203 if (rhythm_ferret) {
1204 rhythm_ferret->set_session (_session);
1207 if (analysis_window) {
1208 analysis_window->set_session (_session);
1212 sfbrowser->set_session (_session);
1215 compute_fixed_ruler_scale ();
1217 /* Make sure we have auto loop and auto punch ranges */
1219 Location* loc = _session->locations()->auto_loop_location();
1221 loc->set_name (_("Loop"));
1224 loc = _session->locations()->auto_punch_location();
1227 loc->set_name (_("Punch"));
1230 refresh_location_display ();
1232 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1233 the selected Marker; this needs the LocationMarker list to be available.
1235 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1236 set_state (*node, Stateful::loading_state_version);
1238 /* catch up with the playhead */
1240 _session->request_locate (playhead_cursor->current_frame ());
1241 _pending_initial_locate = true;
1245 /* These signals can all be emitted by a non-GUI thread. Therefore the
1246 handlers for them must not attempt to directly interact with the GUI,
1247 but use PBD::Signal<T>::connect() which accepts an event loop
1248 ("context") where the handler will be asked to run.
1251 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1252 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1253 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1254 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1255 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1256 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1257 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1258 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1259 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1260 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1261 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1262 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1263 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1264 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1266 playhead_cursor->show ();
1268 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1269 Config->map_parameters (pc);
1270 _session->config.map_parameters (pc);
1272 restore_ruler_visibility ();
1273 //tempo_map_changed (PropertyChange (0));
1274 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1276 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1277 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1280 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1281 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1284 switch (_snap_type) {
1285 case SnapToRegionStart:
1286 case SnapToRegionEnd:
1287 case SnapToRegionSync:
1288 case SnapToRegionBoundary:
1289 build_region_boundary_cache ();
1296 /* register for undo history */
1297 _session->register_with_memento_command_factory(id(), this);
1299 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1301 start_updating_meters ();
1305 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1307 if (a->get_name() == "RegionMenu") {
1308 /* When the main menu's region menu is opened, we setup the actions so that they look right
1309 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1310 so we resensitize all region actions when the entered regionview or the region selection
1311 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1312 happens after the region context menu is opened. So we set a flag here, too.
1316 sensitize_the_right_region_actions ();
1317 _last_region_menu_was_main = true;
1322 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1324 using namespace Menu_Helpers;
1326 void (Editor::*emf)(FadeShape);
1327 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1330 images = &_xfade_in_images;
1331 emf = &Editor::set_fade_in_shape;
1333 images = &_xfade_out_images;
1334 emf = &Editor::set_fade_out_shape;
1339 _("Linear (for highly correlated material)"),
1340 *(*images)[FadeLinear],
1341 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1345 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1349 _("Constant power"),
1350 *(*images)[FadeConstantPower],
1351 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1354 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1359 *(*images)[FadeSymmetric],
1360 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1364 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1369 *(*images)[FadeSlow],
1370 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1373 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1378 *(*images)[FadeFast],
1379 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1382 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 /** Pop up a context menu for when the user clicks on a start crossfade */
1387 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1389 using namespace Menu_Helpers;
1390 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1393 MenuList& items (xfade_in_context_menu.items());
1396 if (arv->audio_region()->fade_in_active()) {
1397 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1399 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1402 items.push_back (SeparatorElem());
1403 fill_xfade_menu (items, true);
1405 xfade_in_context_menu.popup (button, time);
1408 /** Pop up a context menu for when the user clicks on an end crossfade */
1410 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1412 using namespace Menu_Helpers;
1413 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1416 MenuList& items (xfade_out_context_menu.items());
1419 if (arv->audio_region()->fade_out_active()) {
1420 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1422 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1425 items.push_back (SeparatorElem());
1426 fill_xfade_menu (items, false);
1428 xfade_out_context_menu.popup (button, time);
1432 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1434 using namespace Menu_Helpers;
1435 Menu* (Editor::*build_menu_function)();
1438 switch (item_type) {
1440 case RegionViewName:
1441 case RegionViewNameHighlight:
1442 case LeftFrameHandle:
1443 case RightFrameHandle:
1444 if (with_selection) {
1445 build_menu_function = &Editor::build_track_selection_context_menu;
1447 build_menu_function = &Editor::build_track_region_context_menu;
1452 if (with_selection) {
1453 build_menu_function = &Editor::build_track_selection_context_menu;
1455 build_menu_function = &Editor::build_track_context_menu;
1460 if (clicked_routeview->track()) {
1461 build_menu_function = &Editor::build_track_context_menu;
1463 build_menu_function = &Editor::build_track_bus_context_menu;
1468 /* probably shouldn't happen but if it does, we don't care */
1472 menu = (this->*build_menu_function)();
1473 menu->set_name ("ArdourContextMenu");
1475 /* now handle specific situations */
1477 switch (item_type) {
1479 case RegionViewName:
1480 case RegionViewNameHighlight:
1481 case LeftFrameHandle:
1482 case RightFrameHandle:
1483 if (!with_selection) {
1484 if (region_edit_menu_split_item) {
1485 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1486 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1488 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1491 if (region_edit_menu_split_multichannel_item) {
1492 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1493 region_edit_menu_split_multichannel_item->set_sensitive (true);
1495 region_edit_menu_split_multichannel_item->set_sensitive (false);
1508 /* probably shouldn't happen but if it does, we don't care */
1512 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1514 /* Bounce to disk */
1516 using namespace Menu_Helpers;
1517 MenuList& edit_items = menu->items();
1519 edit_items.push_back (SeparatorElem());
1521 switch (clicked_routeview->audio_track()->freeze_state()) {
1522 case AudioTrack::NoFreeze:
1523 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1526 case AudioTrack::Frozen:
1527 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1530 case AudioTrack::UnFrozen:
1531 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1537 if (item_type == StreamItem && clicked_routeview) {
1538 clicked_routeview->build_underlay_menu(menu);
1541 /* When the region menu is opened, we setup the actions so that they look right
1544 sensitize_the_right_region_actions ();
1545 _last_region_menu_was_main = false;
1547 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1548 menu->popup (button, time);
1552 Editor::build_track_context_menu ()
1554 using namespace Menu_Helpers;
1556 MenuList& edit_items = track_context_menu.items();
1559 add_dstream_context_items (edit_items);
1560 return &track_context_menu;
1564 Editor::build_track_bus_context_menu ()
1566 using namespace Menu_Helpers;
1568 MenuList& edit_items = track_context_menu.items();
1571 add_bus_context_items (edit_items);
1572 return &track_context_menu;
1576 Editor::build_track_region_context_menu ()
1578 using namespace Menu_Helpers;
1579 MenuList& edit_items = track_region_context_menu.items();
1582 /* we've just cleared the track region context menu, so the menu that these
1583 two items were on will have disappeared; stop them dangling.
1585 region_edit_menu_split_item = 0;
1586 region_edit_menu_split_multichannel_item = 0;
1588 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1591 boost::shared_ptr<Track> tr;
1592 boost::shared_ptr<Playlist> pl;
1594 if ((tr = rtv->track())) {
1595 add_region_context_items (edit_items, tr);
1599 add_dstream_context_items (edit_items);
1601 return &track_region_context_menu;
1605 Editor::analyze_region_selection ()
1607 if (analysis_window == 0) {
1608 analysis_window = new AnalysisWindow();
1611 analysis_window->set_session(_session);
1613 analysis_window->show_all();
1616 analysis_window->set_regionmode();
1617 analysis_window->analyze();
1619 analysis_window->present();
1623 Editor::analyze_range_selection()
1625 if (analysis_window == 0) {
1626 analysis_window = new AnalysisWindow();
1629 analysis_window->set_session(_session);
1631 analysis_window->show_all();
1634 analysis_window->set_rangemode();
1635 analysis_window->analyze();
1637 analysis_window->present();
1641 Editor::build_track_selection_context_menu ()
1643 using namespace Menu_Helpers;
1644 MenuList& edit_items = track_selection_context_menu.items();
1645 edit_items.clear ();
1647 add_selection_context_items (edit_items);
1648 // edit_items.push_back (SeparatorElem());
1649 // add_dstream_context_items (edit_items);
1651 return &track_selection_context_menu;
1655 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1657 using namespace Menu_Helpers;
1659 /* OK, stick the region submenu at the top of the list, and then add
1663 RegionSelection rs = get_regions_from_selection_and_entered ();
1665 string::size_type pos = 0;
1666 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1668 /* we have to hack up the region name because "_" has a special
1669 meaning for menu titles.
1672 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1673 menu_item_name.replace (pos, 1, "__");
1677 if (_popup_region_menu_item == 0) {
1678 _popup_region_menu_item = new MenuItem (menu_item_name);
1679 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1680 _popup_region_menu_item->show ();
1682 _popup_region_menu_item->set_label (menu_item_name);
1685 const framepos_t position = get_preferred_edit_position (false, true);
1687 edit_items.push_back (*_popup_region_menu_item);
1688 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1689 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1691 edit_items.push_back (SeparatorElem());
1694 /** Add context menu items relevant to selection ranges.
1695 * @param edit_items List to add the items to.
1698 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1700 using namespace Menu_Helpers;
1702 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1703 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1705 edit_items.push_back (SeparatorElem());
1706 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1708 edit_items.push_back (SeparatorElem());
1710 edit_items.push_back (
1712 _("Move Range Start to Previous Region Boundary"),
1713 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1717 edit_items.push_back (
1719 _("Move Range Start to Next Region Boundary"),
1720 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1724 edit_items.push_back (
1726 _("Move Range End to Previous Region Boundary"),
1727 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1731 edit_items.push_back (
1733 _("Move Range End to Next Region Boundary"),
1734 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1738 edit_items.push_back (SeparatorElem());
1739 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1740 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1742 edit_items.push_back (SeparatorElem());
1743 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1745 edit_items.push_back (SeparatorElem());
1746 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1747 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1749 edit_items.push_back (SeparatorElem());
1750 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1752 edit_items.push_back (SeparatorElem());
1753 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1754 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1755 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1757 edit_items.push_back (SeparatorElem());
1758 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1759 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1760 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1761 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1762 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1763 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1764 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1770 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1772 using namespace Menu_Helpers;
1776 Menu *play_menu = manage (new Menu);
1777 MenuList& play_items = play_menu->items();
1778 play_menu->set_name ("ArdourContextMenu");
1780 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1781 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1782 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1783 play_items.push_back (SeparatorElem());
1784 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1786 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1790 Menu *select_menu = manage (new Menu);
1791 MenuList& select_items = select_menu->items();
1792 select_menu->set_name ("ArdourContextMenu");
1794 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1795 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1796 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1797 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1798 select_items.push_back (SeparatorElem());
1799 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1800 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1801 select_items.push_back (SeparatorElem());
1802 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1803 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1804 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1805 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1806 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1807 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1808 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1810 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1814 Menu *cutnpaste_menu = manage (new Menu);
1815 MenuList& cutnpaste_items = cutnpaste_menu->items();
1816 cutnpaste_menu->set_name ("ArdourContextMenu");
1818 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1819 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1820 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1822 cutnpaste_items.push_back (SeparatorElem());
1824 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1825 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1827 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1829 /* Adding new material */
1831 edit_items.push_back (SeparatorElem());
1832 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1833 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1837 Menu *nudge_menu = manage (new Menu());
1838 MenuList& nudge_items = nudge_menu->items();
1839 nudge_menu->set_name ("ArdourContextMenu");
1841 edit_items.push_back (SeparatorElem());
1842 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1843 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1844 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1845 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1847 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1851 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1853 using namespace Menu_Helpers;
1857 Menu *play_menu = manage (new Menu);
1858 MenuList& play_items = play_menu->items();
1859 play_menu->set_name ("ArdourContextMenu");
1861 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1862 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1863 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1867 Menu *select_menu = manage (new Menu);
1868 MenuList& select_items = select_menu->items();
1869 select_menu->set_name ("ArdourContextMenu");
1871 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1872 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1873 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1874 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1875 select_items.push_back (SeparatorElem());
1876 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1877 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1878 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1879 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1881 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1885 Menu *cutnpaste_menu = manage (new Menu);
1886 MenuList& cutnpaste_items = cutnpaste_menu->items();
1887 cutnpaste_menu->set_name ("ArdourContextMenu");
1889 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1890 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1891 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1893 Menu *nudge_menu = manage (new Menu());
1894 MenuList& nudge_items = nudge_menu->items();
1895 nudge_menu->set_name ("ArdourContextMenu");
1897 edit_items.push_back (SeparatorElem());
1898 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1899 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1900 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1901 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1903 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1907 Editor::snap_type() const
1913 Editor::snap_mode() const
1919 Editor::set_snap_to (SnapType st)
1921 unsigned int snap_ind = (unsigned int)st;
1925 if (snap_ind > snap_type_strings.size() - 1) {
1927 _snap_type = (SnapType)snap_ind;
1930 string str = snap_type_strings[snap_ind];
1932 if (str != snap_type_selector.get_text()) {
1933 snap_type_selector.set_text (str);
1938 switch (_snap_type) {
1939 case SnapToBeatDiv128:
1940 case SnapToBeatDiv64:
1941 case SnapToBeatDiv32:
1942 case SnapToBeatDiv28:
1943 case SnapToBeatDiv24:
1944 case SnapToBeatDiv20:
1945 case SnapToBeatDiv16:
1946 case SnapToBeatDiv14:
1947 case SnapToBeatDiv12:
1948 case SnapToBeatDiv10:
1949 case SnapToBeatDiv8:
1950 case SnapToBeatDiv7:
1951 case SnapToBeatDiv6:
1952 case SnapToBeatDiv5:
1953 case SnapToBeatDiv4:
1954 case SnapToBeatDiv3:
1955 case SnapToBeatDiv2: {
1956 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
1957 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
1959 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
1960 current_bbt_points_begin, current_bbt_points_end);
1961 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
1962 current_bbt_points_begin, current_bbt_points_end);
1963 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
1967 case SnapToRegionStart:
1968 case SnapToRegionEnd:
1969 case SnapToRegionSync:
1970 case SnapToRegionBoundary:
1971 build_region_boundary_cache ();
1979 SnapChanged (); /* EMIT SIGNAL */
1983 Editor::set_snap_mode (SnapMode mode)
1985 string str = snap_mode_strings[(int)mode];
1987 if (_internal_editing) {
1988 internal_snap_mode = mode;
1990 pre_internal_snap_mode = mode;
1995 if (str != snap_mode_selector.get_text ()) {
1996 snap_mode_selector.set_text (str);
2002 Editor::set_edit_point_preference (EditPoint ep, bool force)
2004 bool changed = (_edit_point != ep);
2007 string str = edit_point_strings[(int)ep];
2009 if (str != edit_point_selector.get_text ()) {
2010 edit_point_selector.set_text (str);
2013 set_canvas_cursor ();
2015 if (!force && !changed) {
2019 const char* action=NULL;
2021 switch (_edit_point) {
2022 case EditAtPlayhead:
2023 action = "edit-at-playhead";
2025 case EditAtSelectedMarker:
2026 action = "edit-at-marker";
2029 action = "edit-at-mouse";
2033 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2035 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2039 bool in_track_canvas;
2041 if (!mouse_frame (foo, in_track_canvas)) {
2042 in_track_canvas = false;
2045 reset_canvas_action_sensitivity (in_track_canvas);
2051 Editor::set_state (const XMLNode& node, int /*version*/)
2053 const XMLProperty* prop;
2060 g.base_width = default_width;
2061 g.base_height = default_height;
2065 if ((geometry = find_named_node (node, "geometry")) != 0) {
2069 if ((prop = geometry->property("x_size")) == 0) {
2070 prop = geometry->property ("x-size");
2073 g.base_width = atoi(prop->value());
2075 if ((prop = geometry->property("y_size")) == 0) {
2076 prop = geometry->property ("y-size");
2079 g.base_height = atoi(prop->value());
2082 if ((prop = geometry->property ("x_pos")) == 0) {
2083 prop = geometry->property ("x-pos");
2086 x = atoi (prop->value());
2089 if ((prop = geometry->property ("y_pos")) == 0) {
2090 prop = geometry->property ("y-pos");
2093 y = atoi (prop->value());
2097 set_default_size (g.base_width, g.base_height);
2100 if (_session && (prop = node.property ("playhead"))) {
2102 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2103 playhead_cursor->set_position (pos);
2105 playhead_cursor->set_position (0);
2108 if ((prop = node.property ("mixer-width"))) {
2109 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2112 if ((prop = node.property ("zoom-focus"))) {
2113 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2116 if ((prop = node.property ("zoom"))) {
2117 /* older versions of ardour used floating point samples_per_pixel */
2118 double f = PBD::atof (prop->value());
2119 reset_zoom (llrintf (f));
2121 reset_zoom (samples_per_pixel);
2124 if ((prop = node.property ("visible-track-count"))) {
2125 set_visible_track_count (PBD::atoi (prop->value()));
2128 if ((prop = node.property ("snap-to"))) {
2129 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2132 if ((prop = node.property ("snap-mode"))) {
2133 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2136 if ((prop = node.property ("internal-snap-to"))) {
2137 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2140 if ((prop = node.property ("internal-snap-mode"))) {
2141 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2144 if ((prop = node.property ("pre-internal-snap-to"))) {
2145 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2149 if ((prop = node.property ("pre-internal-snap-mode"))) {
2150 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2153 if ((prop = node.property ("mouse-mode"))) {
2154 MouseMode m = str2mousemode(prop->value());
2155 set_mouse_mode (m, true);
2157 set_mouse_mode (MouseObject, true);
2160 if ((prop = node.property ("left-frame")) != 0) {
2162 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2166 reset_x_origin (pos);
2170 if ((prop = node.property ("y-origin")) != 0) {
2171 reset_y_origin (atof (prop->value ()));
2174 if ((prop = node.property ("internal-edit"))) {
2175 bool yn = string_is_affirmative (prop->value());
2176 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2178 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2179 tact->set_active (!yn);
2180 tact->set_active (yn);
2184 if ((prop = node.property ("join-object-range"))) {
2185 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2186 bool yn = string_is_affirmative (prop->value());
2188 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2189 tact->set_active (!yn);
2190 tact->set_active (yn);
2192 set_mouse_mode(mouse_mode, true);
2195 if ((prop = node.property ("edit-point"))) {
2196 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2199 if ((prop = node.property ("show-measures"))) {
2200 bool yn = string_is_affirmative (prop->value());
2201 _show_measures = yn;
2202 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2204 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2205 /* do it twice to force the change */
2206 tact->set_active (!yn);
2207 tact->set_active (yn);
2211 if ((prop = node.property ("follow-playhead"))) {
2212 bool yn = string_is_affirmative (prop->value());
2213 set_follow_playhead (yn);
2214 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2216 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2217 if (tact->get_active() != yn) {
2218 tact->set_active (yn);
2223 if ((prop = node.property ("stationary-playhead"))) {
2224 bool yn = string_is_affirmative (prop->value());
2225 set_stationary_playhead (yn);
2226 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2228 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2229 if (tact->get_active() != yn) {
2230 tact->set_active (yn);
2235 if ((prop = node.property ("region-list-sort-type"))) {
2236 RegionListSortType st;
2237 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2240 if ((prop = node.property ("show-editor-mixer"))) {
2242 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2245 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2246 bool yn = string_is_affirmative (prop->value());
2248 /* do it twice to force the change */
2250 tact->set_active (!yn);
2251 tact->set_active (yn);
2254 if ((prop = node.property ("show-editor-list"))) {
2256 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2259 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2260 bool yn = string_is_affirmative (prop->value());
2262 /* do it twice to force the change */
2264 tact->set_active (!yn);
2265 tact->set_active (yn);
2268 if ((prop = node.property (X_("editor-list-page")))) {
2269 _the_notebook.set_current_page (atoi (prop->value ()));
2272 if ((prop = node.property (X_("show-marker-lines")))) {
2273 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2275 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2276 bool yn = string_is_affirmative (prop->value ());
2278 tact->set_active (!yn);
2279 tact->set_active (yn);
2282 XMLNodeList children = node.children ();
2283 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2284 selection->set_state (**i, Stateful::current_state_version);
2285 _regions->set_state (**i);
2288 if ((prop = node.property ("maximised"))) {
2289 bool yn = string_is_affirmative (prop->value());
2290 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2292 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2293 bool fs = tact && tact->get_active();
2295 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2299 if ((prop = node.property ("nudge-clock-value"))) {
2301 sscanf (prop->value().c_str(), "%" PRId64, &f);
2302 nudge_clock->set (f);
2304 nudge_clock->set_mode (AudioClock::Timecode);
2305 nudge_clock->set (_session->frame_rate() * 5, true);
2312 Editor::get_state ()
2314 XMLNode* node = new XMLNode ("Editor");
2317 id().print (buf, sizeof (buf));
2318 node->add_property ("id", buf);
2320 if (is_realized()) {
2321 Glib::RefPtr<Gdk::Window> win = get_window();
2323 int x, y, width, height;
2324 win->get_root_origin(x, y);
2325 win->get_size(width, height);
2327 XMLNode* geometry = new XMLNode ("geometry");
2329 snprintf(buf, sizeof(buf), "%d", width);
2330 geometry->add_property("x-size", string(buf));
2331 snprintf(buf, sizeof(buf), "%d", height);
2332 geometry->add_property("y-size", string(buf));
2333 snprintf(buf, sizeof(buf), "%d", x);
2334 geometry->add_property("x-pos", string(buf));
2335 snprintf(buf, sizeof(buf), "%d", y);
2336 geometry->add_property("y-pos", string(buf));
2337 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2338 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2339 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2340 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2341 geometry->add_property("edit-vertical-pane-pos", string(buf));
2343 node->add_child_nocopy (*geometry);
2346 maybe_add_mixer_strip_width (*node);
2348 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2350 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2351 node->add_property ("zoom", buf);
2352 node->add_property ("snap-to", enum_2_string (_snap_type));
2353 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2354 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2355 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2356 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2357 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2358 node->add_property ("edit-point", enum_2_string (_edit_point));
2359 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2360 node->add_property ("visible-track-count", buf);
2362 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2363 node->add_property ("playhead", buf);
2364 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2365 node->add_property ("left-frame", buf);
2366 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2367 node->add_property ("y-origin", buf);
2369 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2370 node->add_property ("maximised", _maximised ? "yes" : "no");
2371 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2372 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2373 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2374 node->add_property ("mouse-mode", enum2str(mouse_mode));
2375 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2376 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2378 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2380 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2381 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2384 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2386 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2387 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2390 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2391 node->add_property (X_("editor-list-page"), buf);
2393 if (button_bindings) {
2394 XMLNode* bb = new XMLNode (X_("Buttons"));
2395 button_bindings->save (*bb);
2396 node->add_child_nocopy (*bb);
2399 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2401 node->add_child_nocopy (selection->get_state ());
2402 node->add_child_nocopy (_regions->get_state ());
2404 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2405 node->add_property ("nudge-clock-value", buf);
2410 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2411 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2413 * @return pair: TimeAxisView that y is over, layer index.
2415 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2416 * in stacked or expanded region display mode, otherwise 0.
2418 std::pair<TimeAxisView *, double>
2419 Editor::trackview_by_y_position (double y, bool trackview_relative_offset)
2421 if (!trackview_relative_offset) {
2422 y -= _trackview_group->canvas_origin().y;
2426 return std::make_pair ( (TimeAxisView *) 0, 0);
2429 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2431 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2438 return std::make_pair ( (TimeAxisView *) 0, 0);
2441 /** Snap a position to the grid, if appropriate, taking into account current
2442 * grid settings and also the state of any snap modifier keys that may be pressed.
2443 * @param start Position to snap.
2444 * @param event Event to get current key modifier information from, or 0.
2447 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2449 if (!_session || !event) {
2453 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2454 if (_snap_mode == SnapOff) {
2455 snap_to_internal (start, direction, for_mark);
2458 if (_snap_mode != SnapOff) {
2459 snap_to_internal (start, direction, for_mark);
2465 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2467 if (!_session || _snap_mode == SnapOff) {
2471 snap_to_internal (start, direction, for_mark);
2475 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2477 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2478 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2480 switch (_snap_type) {
2481 case SnapToTimecodeFrame:
2482 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2483 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2485 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2489 case SnapToTimecodeSeconds:
2490 if (_session->config.get_timecode_offset_negative()) {
2491 start += _session->config.get_timecode_offset ();
2493 start -= _session->config.get_timecode_offset ();
2495 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2496 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2498 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2501 if (_session->config.get_timecode_offset_negative()) {
2502 start -= _session->config.get_timecode_offset ();
2504 start += _session->config.get_timecode_offset ();
2508 case SnapToTimecodeMinutes:
2509 if (_session->config.get_timecode_offset_negative()) {
2510 start += _session->config.get_timecode_offset ();
2512 start -= _session->config.get_timecode_offset ();
2514 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2515 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2517 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2519 if (_session->config.get_timecode_offset_negative()) {
2520 start -= _session->config.get_timecode_offset ();
2522 start += _session->config.get_timecode_offset ();
2526 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2532 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2534 const framepos_t one_second = _session->frame_rate();
2535 const framepos_t one_minute = _session->frame_rate() * 60;
2536 framepos_t presnap = start;
2540 switch (_snap_type) {
2541 case SnapToTimecodeFrame:
2542 case SnapToTimecodeSeconds:
2543 case SnapToTimecodeMinutes:
2544 return timecode_snap_to_internal (start, direction, for_mark);
2547 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2548 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2550 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2555 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2556 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2558 start = (framepos_t) floor ((double) start / one_second) * one_second;
2563 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2564 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2566 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2571 start = _session->tempo_map().round_to_bar (start, direction);
2575 start = _session->tempo_map().round_to_beat (start, direction);
2578 case SnapToBeatDiv128:
2579 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2581 case SnapToBeatDiv64:
2582 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2584 case SnapToBeatDiv32:
2585 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2587 case SnapToBeatDiv28:
2588 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2590 case SnapToBeatDiv24:
2591 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2593 case SnapToBeatDiv20:
2594 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2596 case SnapToBeatDiv16:
2597 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2599 case SnapToBeatDiv14:
2600 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2602 case SnapToBeatDiv12:
2603 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2605 case SnapToBeatDiv10:
2606 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2608 case SnapToBeatDiv8:
2609 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2611 case SnapToBeatDiv7:
2612 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2614 case SnapToBeatDiv6:
2615 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2617 case SnapToBeatDiv5:
2618 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2620 case SnapToBeatDiv4:
2621 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2623 case SnapToBeatDiv3:
2624 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2626 case SnapToBeatDiv2:
2627 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2635 _session->locations()->marks_either_side (start, before, after);
2637 if (before == max_framepos && after == max_framepos) {
2638 /* No marks to snap to, so just don't snap */
2640 } else if (before == max_framepos) {
2642 } else if (after == max_framepos) {
2644 } else if (before != max_framepos && after != max_framepos) {
2645 /* have before and after */
2646 if ((start - before) < (after - start)) {
2655 case SnapToRegionStart:
2656 case SnapToRegionEnd:
2657 case SnapToRegionSync:
2658 case SnapToRegionBoundary:
2659 if (!region_boundary_cache.empty()) {
2661 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2662 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2664 if (direction > 0) {
2665 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2667 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2670 if (next != region_boundary_cache.begin ()) {
2675 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2676 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2678 if (start > (p + n) / 2) {
2687 switch (_snap_mode) {
2693 if (presnap > start) {
2694 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2698 } else if (presnap < start) {
2699 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2705 /* handled at entry */
2713 Editor::setup_toolbar ()
2715 HBox* mode_box = manage(new HBox);
2716 mode_box->set_border_width (2);
2717 mode_box->set_spacing(4);
2719 HBox* mouse_mode_box = manage (new HBox);
2720 HBox* mouse_mode_hbox = manage (new HBox);
2721 VBox* mouse_mode_vbox = manage (new VBox);
2722 Alignment* mouse_mode_align = manage (new Alignment);
2724 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2725 // mouse_mode_size_group->add_widget (smart_mode_button);
2726 mouse_mode_size_group->add_widget (mouse_move_button);
2727 mouse_mode_size_group->add_widget (mouse_select_button);
2728 mouse_mode_size_group->add_widget (mouse_zoom_button);
2729 mouse_mode_size_group->add_widget (mouse_gain_button);
2730 mouse_mode_size_group->add_widget (mouse_timefx_button);
2731 mouse_mode_size_group->add_widget (mouse_audition_button);
2732 mouse_mode_size_group->add_widget (mouse_draw_button);
2733 mouse_mode_size_group->add_widget (internal_edit_button);
2735 /* make them just a bit bigger */
2736 mouse_move_button.set_size_request (-1, 30);
2738 mouse_mode_hbox->set_spacing (2);
2740 if (!ARDOUR::Profile->get_trx()) {
2741 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2744 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2745 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2746 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2748 if (!ARDOUR::Profile->get_trx()) {
2749 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2750 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2751 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2752 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2753 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2756 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2758 mouse_mode_align->add (*mouse_mode_vbox);
2759 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2761 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2763 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2764 if (!Profile->get_sae()) {
2765 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2767 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2769 edit_mode_selector.set_name ("mouse mode button");
2770 edit_mode_selector.set_size_request (65, -1);
2771 edit_mode_selector.add_elements (ArdourButton::Inset);
2773 if (!ARDOUR::Profile->get_trx()) {
2774 mode_box->pack_start (edit_mode_selector, false, false);
2776 mode_box->pack_start (*mouse_mode_box, false, false);
2778 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2779 _mouse_mode_tearoff->set_name ("MouseModeBase");
2780 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2782 if (Profile->get_sae()) {
2783 _mouse_mode_tearoff->set_can_be_torn_off (false);
2786 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2787 &_mouse_mode_tearoff->tearoff_window()));
2788 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2789 &_mouse_mode_tearoff->tearoff_window(), 1));
2790 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2791 &_mouse_mode_tearoff->tearoff_window()));
2792 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2793 &_mouse_mode_tearoff->tearoff_window(), 1));
2797 _zoom_box.set_spacing (2);
2798 _zoom_box.set_border_width (2);
2802 zoom_in_button.set_name ("zoom button");
2803 // zoom_in_button.add_elements ( ArdourButton::Inset );
2804 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2805 zoom_in_button.set_image(::get_icon ("zoom_in"));
2806 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2807 zoom_in_button.set_related_action (act);
2809 zoom_out_button.set_name ("zoom button");
2810 // zoom_out_button.add_elements ( ArdourButton::Inset );
2811 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2812 zoom_out_button.set_image(::get_icon ("zoom_out"));
2813 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2814 zoom_out_button.set_related_action (act);
2816 zoom_out_full_button.set_name ("zoom button");
2817 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2818 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2819 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2820 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2821 zoom_out_full_button.set_related_action (act);
2823 zoom_focus_selector.set_name ("zoom button");
2824 zoom_focus_selector.set_size_request (80, -1);
2825 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2827 if (!ARDOUR::Profile->get_trx()) {
2828 _zoom_box.pack_start (zoom_out_button, false, false);
2829 _zoom_box.pack_start (zoom_in_button, false, false);
2830 _zoom_box.pack_start (zoom_out_full_button, false, false);
2831 _zoom_box.pack_start (zoom_focus_selector, false, false);
2833 mode_box->pack_start (zoom_out_button, false, false);
2834 mode_box->pack_start (zoom_in_button, false, false);
2837 /* Track zoom buttons */
2838 visible_tracks_selector.set_name ("zoom button");
2839 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2840 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2842 tav_expand_button.set_name ("zoom button");
2843 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2844 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2845 tav_expand_button.set_size_request (-1, 20);
2846 tav_expand_button.set_image(::get_icon ("tav_exp"));
2847 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2848 tav_expand_button.set_related_action (act);
2850 tav_shrink_button.set_name ("zoom button");
2851 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2852 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2853 tav_shrink_button.set_size_request (-1, 20);
2854 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2855 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2856 tav_shrink_button.set_related_action (act);
2858 if (!ARDOUR::Profile->get_trx()) {
2859 _zoom_box.pack_start (visible_tracks_selector);
2861 _zoom_box.pack_start (tav_shrink_button);
2862 _zoom_box.pack_start (tav_expand_button);
2864 if (!ARDOUR::Profile->get_trx()) {
2865 _zoom_tearoff = manage (new TearOff (_zoom_box));
2867 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2868 &_zoom_tearoff->tearoff_window()));
2869 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2870 &_zoom_tearoff->tearoff_window(), 0));
2871 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window()));
2873 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2874 &_zoom_tearoff->tearoff_window(), 0));
2877 snap_box.set_spacing (2);
2878 snap_box.set_border_width (2);
2880 snap_type_selector.set_name ("mouse mode button");
2881 snap_type_selector.set_size_request (140, -1);
2882 snap_type_selector.add_elements (ArdourButton::Inset);
2884 snap_mode_selector.set_name ("mouse mode button");
2885 snap_mode_selector.set_size_request (85, -1);
2886 snap_mode_selector.add_elements (ArdourButton::Inset);
2888 edit_point_selector.set_name ("mouse mode button");
2889 edit_point_selector.set_size_request (85, -1);
2890 edit_point_selector.add_elements (ArdourButton::Inset);
2892 snap_box.pack_start (snap_mode_selector, false, false);
2893 snap_box.pack_start (snap_type_selector, false, false);
2894 snap_box.pack_start (edit_point_selector, false, false);
2898 HBox *nudge_box = manage (new HBox);
2899 nudge_box->set_spacing (2);
2900 nudge_box->set_border_width (2);
2902 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2903 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2905 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2906 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2908 nudge_box->pack_start (nudge_backward_button, false, false);
2909 nudge_box->pack_start (nudge_forward_button, false, false);
2910 nudge_box->pack_start (*nudge_clock, false, false);
2913 /* Pack everything in... */
2915 HBox* hbox = manage (new HBox);
2916 hbox->set_spacing(10);
2918 _tools_tearoff = manage (new TearOff (*hbox));
2919 _tools_tearoff->set_name ("MouseModeBase");
2920 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2922 if (Profile->get_sae()) {
2923 _tools_tearoff->set_can_be_torn_off (false);
2926 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window()));
2928 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_tools_tearoff->tearoff_window(), 0));
2930 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_tools_tearoff->tearoff_window()));
2932 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_tools_tearoff->tearoff_window(), 0));
2935 toolbar_hbox.set_spacing (10);
2936 toolbar_hbox.set_border_width (1);
2938 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2939 if (!ARDOUR::Profile->get_trx()) {
2940 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2941 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2944 if (!ARDOUR::Profile->get_trx()) {
2945 hbox->pack_start (snap_box, false, false);
2946 if (!Profile->get_small_screen()) {
2947 hbox->pack_start (*nudge_box, false, false);
2949 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2952 hbox->pack_start (panic_box, false, false);
2956 toolbar_base.set_name ("ToolBarBase");
2957 toolbar_base.add (toolbar_hbox);
2959 _toolbar_viewport.add (toolbar_base);
2960 /* stick to the required height but allow width to vary if there's not enough room */
2961 _toolbar_viewport.set_size_request (1, -1);
2963 toolbar_frame.set_shadow_type (SHADOW_OUT);
2964 toolbar_frame.set_name ("BaseFrame");
2965 toolbar_frame.add (_toolbar_viewport);
2969 Editor::build_edit_point_menu ()
2971 using namespace Menu_Helpers;
2973 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
2974 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
2975 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
2979 Editor::build_edit_mode_menu ()
2981 using namespace Menu_Helpers;
2983 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
2984 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
2985 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
2989 Editor::build_snap_mode_menu ()
2991 using namespace Menu_Helpers;
2993 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
2994 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
2995 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
2999 Editor::build_snap_type_menu ()
3001 using namespace Menu_Helpers;
3003 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3004 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3005 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3006 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3007 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3008 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3009 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3010 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3011 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3012 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3013 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3014 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3015 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3016 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3017 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3018 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3019 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3020 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3021 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3022 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3023 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3024 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3025 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3026 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3027 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3028 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3029 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3030 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3031 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3032 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3036 Editor::setup_tooltips ()
3038 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3039 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3040 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3041 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3042 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3043 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3044 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3045 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3046 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3047 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3048 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3049 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3050 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3051 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3052 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3053 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3054 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3055 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3056 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3057 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3058 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3059 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3060 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3061 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3065 Editor::convert_drop_to_paths (
3066 vector<string>& paths,
3067 const RefPtr<Gdk::DragContext>& /*context*/,
3070 const SelectionData& data,
3074 if (_session == 0) {
3078 vector<string> uris = data.get_uris();
3082 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3083 are actually URI lists. So do it by hand.
3086 if (data.get_target() != "text/plain") {
3090 /* Parse the "uri-list" format that Nautilus provides,
3091 where each pathname is delimited by \r\n.
3093 THERE MAY BE NO NULL TERMINATING CHAR!!!
3096 string txt = data.get_text();
3100 p = (char *) malloc (txt.length() + 1);
3101 txt.copy (p, txt.length(), 0);
3102 p[txt.length()] = '\0';
3108 while (g_ascii_isspace (*p))
3112 while (*q && (*q != '\n') && (*q != '\r')) {
3119 while (q > p && g_ascii_isspace (*q))
3124 uris.push_back (string (p, q - p + 1));
3128 p = strchr (p, '\n');
3140 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3141 if ((*i).substr (0,7) == "file://") {
3142 paths.push_back (Glib::filename_from_uri (*i));
3150 Editor::new_tempo_section ()
3155 Editor::map_transport_state ()
3157 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3159 if (_session && _session->transport_stopped()) {
3160 have_pending_keyboard_selection = false;
3163 update_loop_range_view ();
3169 Editor::begin_reversible_command (string name)
3172 _session->begin_reversible_command (name);
3177 Editor::begin_reversible_command (GQuark q)
3180 _session->begin_reversible_command (q);
3185 Editor::commit_reversible_command ()
3188 _session->commit_reversible_command ();
3193 Editor::history_changed ()
3197 if (undo_action && _session) {
3198 if (_session->undo_depth() == 0) {
3199 label = S_("Command|Undo");
3201 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3203 undo_action->property_label() = label;
3206 if (redo_action && _session) {
3207 if (_session->redo_depth() == 0) {
3210 label = string_compose(_("Redo (%1)"), _session->next_redo());
3212 redo_action->property_label() = label;
3217 Editor::duplicate_range (bool with_dialog)
3221 RegionSelection rs = get_regions_from_selection_and_entered ();
3223 if ( selection->time.length() == 0 && rs.empty()) {
3229 ArdourDialog win (_("Duplicate"));
3230 Label label (_("Number of duplications:"));
3231 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3232 SpinButton spinner (adjustment, 0.0, 1);
3235 win.get_vbox()->set_spacing (12);
3236 win.get_vbox()->pack_start (hbox);
3237 hbox.set_border_width (6);
3238 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3240 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3241 place, visually. so do this by hand.
3244 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3245 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3246 spinner.grab_focus();
3252 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3253 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3254 win.set_default_response (RESPONSE_ACCEPT);
3256 spinner.grab_focus ();
3258 switch (win.run ()) {
3259 case RESPONSE_ACCEPT:
3265 times = adjustment.get_value();
3268 if ((current_mouse_mode() == Editing::MouseRange)) {
3269 if (selection->time.length()) {
3270 duplicate_selection (times);
3272 } else if (get_smart_mode()) {
3273 if (selection->time.length()) {
3274 duplicate_selection (times);
3276 duplicate_some_regions (rs, times);
3278 duplicate_some_regions (rs, times);
3283 Editor::set_edit_mode (EditMode m)
3285 Config->set_edit_mode (m);
3289 Editor::cycle_edit_mode ()
3291 switch (Config->get_edit_mode()) {
3293 if (Profile->get_sae()) {
3294 Config->set_edit_mode (Lock);
3296 Config->set_edit_mode (Splice);
3300 Config->set_edit_mode (Lock);
3303 Config->set_edit_mode (Slide);
3309 Editor::edit_mode_selection_done ( EditMode m )
3311 Config->set_edit_mode ( m );
3315 Editor::snap_type_selection_done (SnapType snaptype)
3317 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3319 ract->set_active ();
3324 Editor::snap_mode_selection_done (SnapMode mode)
3326 RefPtr<RadioAction> ract = snap_mode_action (mode);
3329 ract->set_active (true);
3334 Editor::cycle_edit_point (bool with_marker)
3336 switch (_edit_point) {
3338 set_edit_point_preference (EditAtPlayhead);
3340 case EditAtPlayhead:
3342 set_edit_point_preference (EditAtSelectedMarker);
3344 set_edit_point_preference (EditAtMouse);
3347 case EditAtSelectedMarker:
3348 set_edit_point_preference (EditAtMouse);
3354 Editor::edit_point_selection_done (EditPoint ep)
3356 set_edit_point_preference ( ep );
3360 Editor::build_zoom_focus_menu ()
3362 using namespace Menu_Helpers;
3364 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3365 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3366 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3367 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3368 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3369 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3373 Editor::zoom_focus_selection_done ( ZoomFocus f )
3375 RefPtr<RadioAction> ract = zoom_focus_action (f);
3377 ract->set_active ();
3382 Editor::build_track_count_menu ()
3384 using namespace Menu_Helpers;
3386 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3387 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3388 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3389 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3390 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3391 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3392 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3393 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3394 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3395 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3396 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3397 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3401 Editor::set_visible_track_count (int32_t n)
3403 _visible_track_count = n;
3405 /* if the canvas hasn't really been allocated any size yet, just
3406 record the desired number of visible tracks and return. when canvas
3407 allocation happens, we will get called again and then we can do the
3411 if (_visible_canvas_height <= 1) {
3418 if (_visible_track_count > 0) {
3419 h = _visible_canvas_height / _visible_track_count;
3420 std::ostringstream s;
3421 s << _visible_track_count;
3423 } else if (_visible_track_count == 0) {
3424 h = _visible_canvas_height / track_views.size();
3427 /* negative value means that the visible track count has
3428 been overridden by explicit track height changes.
3430 visible_tracks_selector.set_text (X_("*"));
3434 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3435 (*i)->set_height (h);
3438 if (str != visible_tracks_selector.get_text()) {
3439 visible_tracks_selector.set_text (str);
3444 Editor::override_visible_track_count ()
3446 _visible_track_count = -_visible_track_count;
3450 Editor::edit_controls_button_release (GdkEventButton* ev)
3452 if (Keyboard::is_context_menu_event (ev)) {
3453 ARDOUR_UI::instance()->add_route (this);
3454 } else if (ev->button == 1) {
3455 selection->clear_tracks ();
3462 Editor::mouse_select_button_release (GdkEventButton* ev)
3464 /* this handles just right-clicks */
3466 if (ev->button != 3) {
3474 Editor::set_zoom_focus (ZoomFocus f)
3476 string str = zoom_focus_strings[(int)f];
3478 if (str != zoom_focus_selector.get_text()) {
3479 zoom_focus_selector.set_text (str);
3482 if (zoom_focus != f) {
3489 Editor::cycle_zoom_focus ()
3491 switch (zoom_focus) {
3493 set_zoom_focus (ZoomFocusRight);
3495 case ZoomFocusRight:
3496 set_zoom_focus (ZoomFocusCenter);
3498 case ZoomFocusCenter:
3499 set_zoom_focus (ZoomFocusPlayhead);
3501 case ZoomFocusPlayhead:
3502 set_zoom_focus (ZoomFocusMouse);
3504 case ZoomFocusMouse:
3505 set_zoom_focus (ZoomFocusEdit);
3508 set_zoom_focus (ZoomFocusLeft);
3514 Editor::ensure_float (Window& win)
3516 win.set_transient_for (*this);
3520 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3522 /* recover or initialize pane positions. do this here rather than earlier because
3523 we don't want the positions to change the child allocations, which they seem to do.
3529 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3538 XMLNode* geometry = find_named_node (*node, "geometry");
3540 if (which == static_cast<Paned*> (&edit_pane)) {
3542 if (done & Horizontal) {
3546 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3547 _notebook_shrunk = string_is_affirmative (prop->value ());
3550 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3551 /* initial allocation is 90% to canvas, 10% to notebook */
3552 pos = (int) floor (alloc.get_width() * 0.90f);
3553 snprintf (buf, sizeof(buf), "%d", pos);
3555 pos = atoi (prop->value());
3558 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3559 edit_pane.set_position (pos);
3562 done = (Pane) (done | Horizontal);
3564 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3566 if (done & Vertical) {
3570 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3571 /* initial allocation is 90% to canvas, 10% to summary */
3572 pos = (int) floor (alloc.get_height() * 0.90f);
3573 snprintf (buf, sizeof(buf), "%d", pos);
3576 pos = atoi (prop->value());
3579 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3580 editor_summary_pane.set_position (pos);
3583 done = (Pane) (done | Vertical);
3588 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3590 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3591 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3592 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3593 top_hbox.remove (toolbar_frame);
3598 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3600 if (toolbar_frame.get_parent() == 0) {
3601 top_hbox.pack_end (toolbar_frame);
3606 Editor::set_show_measures (bool yn)
3608 if (_show_measures != yn) {
3611 if ((_show_measures = yn) == true) {
3613 tempo_lines->show();
3616 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3617 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3619 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3620 draw_measures (begin, end);
3628 Editor::toggle_follow_playhead ()
3630 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3632 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3633 set_follow_playhead (tact->get_active());
3637 /** @param yn true to follow playhead, otherwise false.
3638 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3641 Editor::set_follow_playhead (bool yn, bool catch_up)
3643 if (_follow_playhead != yn) {
3644 if ((_follow_playhead = yn) == true && catch_up) {
3646 reset_x_origin_to_follow_playhead ();
3653 Editor::toggle_stationary_playhead ()
3655 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3657 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3658 set_stationary_playhead (tact->get_active());
3663 Editor::set_stationary_playhead (bool yn)
3665 if (_stationary_playhead != yn) {
3666 if ((_stationary_playhead = yn) == true) {
3668 // FIXME need a 3.0 equivalent of this 2.X call
3669 // update_current_screen ();
3676 Editor::playlist_selector () const
3678 return *_playlist_selector;
3682 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3686 switch (_snap_type) {
3691 case SnapToBeatDiv128:
3694 case SnapToBeatDiv64:
3697 case SnapToBeatDiv32:
3700 case SnapToBeatDiv28:
3703 case SnapToBeatDiv24:
3706 case SnapToBeatDiv20:
3709 case SnapToBeatDiv16:
3712 case SnapToBeatDiv14:
3715 case SnapToBeatDiv12:
3718 case SnapToBeatDiv10:
3721 case SnapToBeatDiv8:
3724 case SnapToBeatDiv7:
3727 case SnapToBeatDiv6:
3730 case SnapToBeatDiv5:
3733 case SnapToBeatDiv4:
3736 case SnapToBeatDiv3:
3739 case SnapToBeatDiv2:
3745 return _session->tempo_map().meter_at (position).divisions_per_bar();
3750 case SnapToTimecodeFrame:
3751 case SnapToTimecodeSeconds:
3752 case SnapToTimecodeMinutes:
3755 case SnapToRegionStart:
3756 case SnapToRegionEnd:
3757 case SnapToRegionSync:
3758 case SnapToRegionBoundary:
3768 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3772 ret = nudge_clock->current_duration (pos);
3773 next = ret + 1; /* XXXX fix me */
3779 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3781 ArdourDialog dialog (_("Playlist Deletion"));
3782 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3783 "If it is kept, its audio files will not be cleaned.\n"
3784 "If it is deleted, audio files used by it alone will be cleaned."),
3787 dialog.set_position (WIN_POS_CENTER);
3788 dialog.get_vbox()->pack_start (label);
3792 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3793 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3794 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3796 switch (dialog.run ()) {
3797 case RESPONSE_ACCEPT:
3798 /* delete the playlist */
3802 case RESPONSE_REJECT:
3803 /* keep the playlist */
3815 Editor::audio_region_selection_covers (framepos_t where)
3817 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3818 if ((*a)->region()->covers (where)) {
3827 Editor::prepare_for_cleanup ()
3829 cut_buffer->clear_regions ();
3830 cut_buffer->clear_playlists ();
3832 selection->clear_regions ();
3833 selection->clear_playlists ();
3835 _regions->suspend_redisplay ();
3839 Editor::finish_cleanup ()
3841 _regions->resume_redisplay ();
3845 Editor::transport_loop_location()
3848 return _session->locations()->auto_loop_location();
3855 Editor::transport_punch_location()
3858 return _session->locations()->auto_punch_location();
3865 Editor::control_layout_scroll (GdkEventScroll* ev)
3867 /* Just forward to the normal canvas scroll method. The coordinate
3868 systems are different but since the canvas is always larger than the
3869 track headers, and aligned with the trackview area, this will work.
3871 In the not too distant future this layout is going away anyway and
3872 headers will be on the canvas.
3874 return canvas_scroll_event (ev);
3878 Editor::session_state_saved (string)
3881 _snapshots->redisplay ();
3885 Editor::update_tearoff_visibility()
3887 bool visible = Config->get_keep_tearoffs();
3888 _mouse_mode_tearoff->set_visible (visible);
3889 _tools_tearoff->set_visible (visible);
3890 if (_zoom_tearoff) {
3891 _zoom_tearoff->set_visible (visible);
3896 Editor::maximise_editing_space ()
3908 Editor::restore_editing_space ()
3920 * Make new playlists for a given track and also any others that belong
3921 * to the same active route group with the `select' property.
3926 Editor::new_playlists (TimeAxisView* v)
3928 begin_reversible_command (_("new playlists"));
3929 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3930 _session->playlists->get (playlists);
3931 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3932 commit_reversible_command ();
3936 * Use a copy of the current playlist for a given track and also any others that belong
3937 * to the same active route group with the `select' property.
3942 Editor::copy_playlists (TimeAxisView* v)
3944 begin_reversible_command (_("copy playlists"));
3945 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3946 _session->playlists->get (playlists);
3947 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3948 commit_reversible_command ();
3951 /** Clear the current playlist for a given track and also any others that belong
3952 * to the same active route group with the `select' property.
3957 Editor::clear_playlists (TimeAxisView* v)
3959 begin_reversible_command (_("clear playlists"));
3960 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3961 _session->playlists->get (playlists);
3962 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
3963 commit_reversible_command ();
3967 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3969 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3973 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3975 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3979 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
3981 atv.clear_playlist ();
3985 Editor::on_key_press_event (GdkEventKey* ev)
3987 return key_press_focus_accelerator_handler (*this, ev);
3991 Editor::on_key_release_event (GdkEventKey* ev)
3993 return Gtk::Window::on_key_release_event (ev);
3994 // return key_press_focus_accelerator_handler (*this, ev);
3997 /** Queue up a change to the viewport x origin.
3998 * @param frame New x origin.
4001 Editor::reset_x_origin (framepos_t frame)
4003 pending_visual_change.add (VisualChange::TimeOrigin);
4004 pending_visual_change.time_origin = frame;
4005 ensure_visual_change_idle_handler ();
4009 Editor::reset_y_origin (double y)
4011 pending_visual_change.add (VisualChange::YOrigin);
4012 pending_visual_change.y_origin = y;
4013 ensure_visual_change_idle_handler ();
4017 Editor::reset_zoom (framecnt_t spp)
4019 clamp_samples_per_pixel (spp);
4021 if (spp == samples_per_pixel) {
4025 pending_visual_change.add (VisualChange::ZoomLevel);
4026 pending_visual_change.samples_per_pixel = spp;
4027 ensure_visual_change_idle_handler ();
4031 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4033 reset_x_origin (frame);
4036 if (!no_save_visual) {
4037 undo_visual_stack.push_back (current_visual_state(false));
4041 Editor::VisualState::VisualState (bool with_tracks)
4042 : gui_state (with_tracks ? new GUIObjectState : 0)
4046 Editor::VisualState::~VisualState ()
4051 Editor::VisualState*
4052 Editor::current_visual_state (bool with_tracks)
4054 VisualState* vs = new VisualState (with_tracks);
4055 vs->y_position = vertical_adjustment.get_value();
4056 vs->samples_per_pixel = samples_per_pixel;
4057 vs->leftmost_frame = leftmost_frame;
4058 vs->zoom_focus = zoom_focus;
4061 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4068 Editor::undo_visual_state ()
4070 if (undo_visual_stack.empty()) {
4074 VisualState* vs = undo_visual_stack.back();
4075 undo_visual_stack.pop_back();
4078 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4080 use_visual_state (*vs);
4084 Editor::redo_visual_state ()
4086 if (redo_visual_stack.empty()) {
4090 VisualState* vs = redo_visual_stack.back();
4091 redo_visual_stack.pop_back();
4093 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4095 use_visual_state (*vs);
4099 Editor::swap_visual_state ()
4101 if (undo_visual_stack.empty()) {
4102 redo_visual_state ();
4104 undo_visual_state ();
4109 Editor::use_visual_state (VisualState& vs)
4111 PBD::Unwinder<bool> nsv (no_save_visual, true);
4113 _routes->suspend_redisplay ();
4115 vertical_adjustment.set_value (vs.y_position);
4117 set_zoom_focus (vs.zoom_focus);
4118 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4121 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4123 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4124 (*i)->reset_visual_state ();
4128 _routes->update_visibility ();
4129 _routes->resume_redisplay ();
4132 /** This is the core function that controls the zoom level of the canvas. It is called
4133 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4134 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4137 Editor::set_samples_per_pixel (framecnt_t spp)
4139 clamp_samples_per_pixel (spp);
4140 samples_per_pixel = spp;
4143 tempo_lines->tempo_map_changed();
4146 /* convert fpu to frame count */
4148 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4150 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4151 zoom_range_clock->set (frames);
4154 bool const showing_time_selection = selection->time.length() > 0;
4156 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4157 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4158 (*i)->reshow_selection (selection->time);
4162 ZoomChanged (); /* EMIT_SIGNAL */
4164 ArdourCanvas::GtkCanvasViewport* c;
4166 c = get_track_canvas();
4168 c->canvas()->zoomed ();
4171 if (playhead_cursor) {
4172 playhead_cursor->set_position (playhead_cursor->current_frame ());
4175 refresh_location_display();
4176 _summary->set_overlays_dirty ();
4178 update_marker_labels ();
4184 Editor::queue_visual_videotimeline_update ()
4187 * pending_visual_change.add (VisualChange::VideoTimeline);
4188 * or maybe even more specific: which videotimeline-image
4189 * currently it calls update_video_timeline() to update
4190 * _all outdated_ images on the video-timeline.
4191 * see 'exposeimg()' in video_image_frame.cc
4193 ensure_visual_change_idle_handler ();
4197 Editor::ensure_visual_change_idle_handler ()
4199 if (pending_visual_change.idle_handler_id < 0) {
4200 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4201 pending_visual_change.being_handled = false;
4206 Editor::_idle_visual_changer (void* arg)
4208 return static_cast<Editor*>(arg)->idle_visual_changer ();
4212 Editor::idle_visual_changer ()
4214 /* set_horizontal_position() below (and maybe other calls) call
4215 gtk_main_iteration(), so it's possible that a signal will be handled
4216 half-way through this method. If this signal wants an
4217 idle_visual_changer we must schedule another one after this one, so
4218 mark the idle_handler_id as -1 here to allow that. Also make a note
4219 that we are doing the visual change, so that changes in response to
4220 super-rapid-screen-update can be dropped if we are still processing
4224 pending_visual_change.idle_handler_id = -1;
4225 pending_visual_change.being_handled = true;
4227 VisualChange vc = pending_visual_change;
4229 pending_visual_change.pending = (VisualChange::Type) 0;
4231 visual_changer (vc);
4233 pending_visual_change.being_handled = false;
4235 return 0; /* this is always a one-shot call */
4239 Editor::visual_changer (const VisualChange& vc)
4241 double const last_time_origin = horizontal_position ();
4243 if (vc.pending & VisualChange::ZoomLevel) {
4244 set_samples_per_pixel (vc.samples_per_pixel);
4246 compute_fixed_ruler_scale ();
4248 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4249 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4251 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4252 current_bbt_points_begin, current_bbt_points_end);
4253 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4254 current_bbt_points_begin, current_bbt_points_end);
4255 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4257 update_video_timeline();
4260 if (vc.pending & VisualChange::TimeOrigin) {
4261 set_horizontal_position (vc.time_origin / samples_per_pixel);
4264 if (vc.pending & VisualChange::YOrigin) {
4265 vertical_adjustment.set_value (vc.y_origin);
4268 if (last_time_origin == horizontal_position ()) {
4269 /* changed signal not emitted */
4270 update_fixed_rulers ();
4271 redisplay_tempo (true);
4274 if (!(vc.pending & VisualChange::ZoomLevel)) {
4275 update_video_timeline();
4278 _summary->set_overlays_dirty ();
4281 struct EditorOrderTimeAxisSorter {
4282 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4283 return a->order () < b->order ();
4288 Editor::sort_track_selection (TrackViewList& sel)
4290 EditorOrderTimeAxisSorter cmp;
4295 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4298 framepos_t where = 0;
4299 EditPoint ep = _edit_point;
4301 if (from_context_menu && (ep == EditAtMouse)) {
4302 return canvas_event_sample (&context_click_event, 0, 0);
4305 if (entered_marker) {
4306 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4307 return entered_marker->position();
4310 if (ignore_playhead && ep == EditAtPlayhead) {
4311 ep = EditAtSelectedMarker;
4315 case EditAtPlayhead:
4316 where = _session->audible_frame();
4317 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4320 case EditAtSelectedMarker:
4321 if (!selection->markers.empty()) {
4323 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4326 where = loc->start();
4330 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4338 if (!mouse_frame (where, ignored)) {
4339 /* XXX not right but what can we do ? */
4343 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4351 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4353 if (!_session) return;
4355 begin_reversible_command (cmd);
4359 if ((tll = transport_loop_location()) == 0) {
4360 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4361 XMLNode &before = _session->locations()->get_state();
4362 _session->locations()->add (loc, true);
4363 _session->set_auto_loop_location (loc);
4364 XMLNode &after = _session->locations()->get_state();
4365 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4367 XMLNode &before = tll->get_state();
4368 tll->set_hidden (false, this);
4369 tll->set (start, end);
4370 XMLNode &after = tll->get_state();
4371 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4374 commit_reversible_command ();
4378 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4380 if (!_session) return;
4382 begin_reversible_command (cmd);
4386 if ((tpl = transport_punch_location()) == 0) {
4387 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4388 XMLNode &before = _session->locations()->get_state();
4389 _session->locations()->add (loc, true);
4390 _session->set_auto_punch_location (loc);
4391 XMLNode &after = _session->locations()->get_state();
4392 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4395 XMLNode &before = tpl->get_state();
4396 tpl->set_hidden (false, this);
4397 tpl->set (start, end);
4398 XMLNode &after = tpl->get_state();
4399 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4402 commit_reversible_command ();
4405 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4406 * @param rs List to which found regions are added.
4407 * @param where Time to look at.
4408 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4411 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4413 const TrackViewList* tracks;
4416 tracks = &track_views;
4421 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4423 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4426 boost::shared_ptr<Track> tr;
4427 boost::shared_ptr<Playlist> pl;
4429 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4431 boost::shared_ptr<RegionList> regions = pl->regions_at (
4432 (framepos_t) floor ( (double) where * tr->speed()));
4434 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4435 RegionView* rv = rtv->view()->find_view (*i);
4446 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4448 const TrackViewList* tracks;
4451 tracks = &track_views;
4456 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4457 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4459 boost::shared_ptr<Track> tr;
4460 boost::shared_ptr<Playlist> pl;
4462 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4464 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4465 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4467 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4469 RegionView* rv = rtv->view()->find_view (*i);
4480 /** Get regions using the following method:
4482 * Make a region list using the selected regions, unless
4483 * the edit point is `mouse' and the mouse is over an unselected
4484 * region. In this case, use just that region.
4486 * If the edit point is not 'mouse', and there are no regions selected,
4487 * search the list of selected tracks and return regions that are under
4488 * the edit point on these tracks. If there are no selected tracks and
4489 * 'No Selection = All Tracks' is active, search all tracks,
4491 * The rationale here is that the mouse edit point is special in that
4492 * its position describes both a time and a track; the other edit
4493 * modes only describe a time. Hence if the edit point is `mouse' we
4494 * ignore selected tracks, as we assume the user means something by
4495 * pointing at a particular track. Also in this case we take note of
4496 * the region directly under the edit point, as there is always just one
4497 * (rather than possibly several with non-mouse edit points).
4501 Editor::get_regions_from_selection_and_edit_point ()
4503 RegionSelection regions;
4505 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4506 regions.add (entered_regionview);
4508 regions = selection->regions;
4512 if (regions.empty() && _edit_point != EditAtMouse) {
4513 TrackViewList tracks = selection->tracks;
4515 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4516 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4517 * is enabled, so consider all tracks
4519 tracks = track_views;
4522 if (!tracks.empty()) {
4523 /* no region selected or entered, but some selected tracks:
4524 * act on all regions on the selected tracks at the edit point
4526 framepos_t const where = get_preferred_edit_position ();
4527 get_regions_at(regions, where, tracks);
4533 /** Start with regions that are selected, or the entered regionview if none are selected.
4534 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4535 * of the regions that we started with.
4539 Editor::get_regions_from_selection_and_entered ()
4541 RegionSelection regions = selection->regions;
4543 if (regions.empty() && entered_regionview) {
4544 regions.add (entered_regionview);
4551 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4553 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4555 RouteTimeAxisView* tatv;
4557 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4559 boost::shared_ptr<Playlist> pl;
4560 vector<boost::shared_ptr<Region> > results;
4562 boost::shared_ptr<Track> tr;
4564 if ((tr = tatv->track()) == 0) {
4569 if ((pl = (tr->playlist())) != 0) {
4570 if (src_comparison) {
4571 pl->get_source_equivalent_regions (region, results);
4573 pl->get_region_list_equivalent_regions (region, results);
4577 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4578 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4579 regions.push_back (marv);
4588 Editor::show_rhythm_ferret ()
4590 if (rhythm_ferret == 0) {
4591 rhythm_ferret = new RhythmFerret(*this);
4594 rhythm_ferret->set_session (_session);
4595 rhythm_ferret->show ();
4596 rhythm_ferret->present ();
4600 Editor::first_idle ()
4602 MessageDialog* dialog = 0;
4604 if (track_views.size() > 1) {
4605 dialog = new MessageDialog (
4607 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4611 ARDOUR_UI::instance()->flush_pending ();
4614 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4618 // first idle adds route children (automation tracks), so we need to redisplay here
4619 _routes->redisplay ();
4626 Editor::_idle_resize (gpointer arg)
4628 return ((Editor*)arg)->idle_resize ();
4632 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4634 if (resize_idle_id < 0) {
4635 resize_idle_id = g_idle_add (_idle_resize, this);
4636 _pending_resize_amount = 0;
4639 /* make a note of the smallest resulting height, so that we can clamp the
4640 lower limit at TimeAxisView::hSmall */
4642 int32_t min_resulting = INT32_MAX;
4644 _pending_resize_amount += h;
4645 _pending_resize_view = view;
4647 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4649 if (selection->tracks.contains (_pending_resize_view)) {
4650 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4651 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4655 if (min_resulting < 0) {
4660 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4661 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4665 /** Handle pending resizing of tracks */
4667 Editor::idle_resize ()
4669 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4671 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4672 selection->tracks.contains (_pending_resize_view)) {
4674 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4675 if (*i != _pending_resize_view) {
4676 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4681 _pending_resize_amount = 0;
4682 _group_tabs->set_dirty ();
4683 resize_idle_id = -1;
4691 ENSURE_GUI_THREAD (*this, &Editor::located);
4694 playhead_cursor->set_position (_session->audible_frame ());
4695 if (_follow_playhead && !_pending_initial_locate) {
4696 reset_x_origin_to_follow_playhead ();
4700 _pending_locate_request = false;
4701 _pending_initial_locate = false;
4705 Editor::region_view_added (RegionView *)
4707 _summary->set_dirty ();
4711 Editor::region_view_removed ()
4713 _summary->set_dirty ();
4717 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4719 TrackViewList::const_iterator j = track_views.begin ();
4720 while (j != track_views.end()) {
4721 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4722 if (rtv && rtv->route() == r) {
4733 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4737 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4738 TimeAxisView* tv = axis_view_from_route (*i);
4748 Editor::add_routes (RouteList& routes)
4750 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4752 RouteTimeAxisView *rtv;
4753 list<RouteTimeAxisView*> new_views;
4755 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4756 boost::shared_ptr<Route> route = (*x);
4758 if (route->is_auditioner() || route->is_monitor()) {
4762 DataType dt = route->input()->default_type();
4764 if (dt == ARDOUR::DataType::AUDIO) {
4765 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4766 rtv->set_route (route);
4767 } else if (dt == ARDOUR::DataType::MIDI) {
4768 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4769 rtv->set_route (route);
4771 throw unknown_type();
4774 new_views.push_back (rtv);
4775 track_views.push_back (rtv);
4777 rtv->effective_gain_display ();
4779 if (internal_editing()) {
4780 rtv->enter_internal_edit_mode ();
4782 rtv->leave_internal_edit_mode ();
4785 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4786 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4789 if (new_views.size() > 0) {
4790 _routes->routes_added (new_views);
4791 _summary->routes_added (new_views);
4794 if (show_editor_mixer_when_tracks_arrive) {
4795 show_editor_mixer (true);
4798 editor_list_button.set_sensitive (true);
4802 Editor::timeaxisview_deleted (TimeAxisView *tv)
4804 if (_session && _session->deletion_in_progress()) {
4805 /* the situation is under control */
4809 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4811 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4813 _routes->route_removed (tv);
4815 if (tv == entered_track) {
4819 TimeAxisView::Children c = tv->get_child_list ();
4820 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4821 if (entered_track == i->get()) {
4826 /* remove it from the list of track views */
4828 TrackViewList::iterator i;
4830 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4831 i = track_views.erase (i);
4834 /* update whatever the current mixer strip is displaying, if revelant */
4836 boost::shared_ptr<Route> route;
4839 route = rtav->route ();
4842 if (current_mixer_strip && current_mixer_strip->route() == route) {
4844 TimeAxisView* next_tv;
4846 if (track_views.empty()) {
4848 } else if (i == track_views.end()) {
4849 next_tv = track_views.front();
4856 set_selected_mixer_strip (*next_tv);
4858 /* make the editor mixer strip go away setting the
4859 * button to inactive (which also unticks the menu option)
4862 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4868 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4870 if (apply_to_selection) {
4871 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4873 TrackSelection::iterator j = i;
4876 hide_track_in_display (*i, false);
4881 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4883 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4884 // this will hide the mixer strip
4885 set_selected_mixer_strip (*tv);
4888 _routes->hide_track_in_display (*tv);
4893 Editor::sync_track_view_list_and_routes ()
4895 track_views = TrackViewList (_routes->views ());
4897 _summary->set_dirty ();
4898 _group_tabs->set_dirty ();
4900 return false; // do not call again (until needed)
4904 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4906 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4911 /** Find a RouteTimeAxisView by the ID of its route */
4913 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4915 RouteTimeAxisView* v;
4917 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4918 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4919 if(v->route()->id() == id) {
4929 Editor::fit_route_group (RouteGroup *g)
4931 TrackViewList ts = axis_views_from_routes (g->route_list ());
4936 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4938 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4941 _session->cancel_audition ();
4945 if (_session->is_auditioning()) {
4946 _session->cancel_audition ();
4947 if (r == last_audition_region) {
4952 _session->audition_region (r);
4953 last_audition_region = r;
4958 Editor::hide_a_region (boost::shared_ptr<Region> r)
4960 r->set_hidden (true);
4964 Editor::show_a_region (boost::shared_ptr<Region> r)
4966 r->set_hidden (false);
4970 Editor::audition_region_from_region_list ()
4972 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4976 Editor::hide_region_from_region_list ()
4978 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
4982 Editor::show_region_in_region_list ()
4984 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
4988 Editor::step_edit_status_change (bool yn)
4991 start_step_editing ();
4993 stop_step_editing ();
4998 Editor::start_step_editing ()
5000 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5004 Editor::stop_step_editing ()
5006 step_edit_connection.disconnect ();
5010 Editor::check_step_edit ()
5012 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5013 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5015 mtv->check_step_edit ();
5019 return true; // do it again, till we stop
5023 Editor::scroll_press (Direction dir)
5025 ++_scroll_callbacks;
5027 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5028 /* delay the first auto-repeat */
5034 scroll_backward (1);
5042 scroll_tracks_up_line ();
5046 scroll_tracks_down_line ();
5050 /* do hacky auto-repeat */
5051 if (!_scroll_connection.connected ()) {
5053 _scroll_connection = Glib::signal_timeout().connect (
5054 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5057 _scroll_callbacks = 0;
5064 Editor::scroll_release ()
5066 _scroll_connection.disconnect ();
5069 /** Queue a change for the Editor viewport x origin to follow the playhead */
5071 Editor::reset_x_origin_to_follow_playhead ()
5073 framepos_t const frame = playhead_cursor->current_frame ();
5075 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5077 if (_session->transport_speed() < 0) {
5079 if (frame > (current_page_samples() / 2)) {
5080 center_screen (frame-(current_page_samples()/2));
5082 center_screen (current_page_samples()/2);
5089 if (frame < leftmost_frame) {
5091 if (_session->transport_rolling()) {
5092 /* rolling; end up with the playhead at the right of the page */
5093 l = frame - current_page_samples ();
5095 /* not rolling: end up with the playhead 1/4 of the way along the page */
5096 l = frame - current_page_samples() / 4;
5100 if (_session->transport_rolling()) {
5101 /* rolling: end up with the playhead on the left of the page */
5104 /* not rolling: end up with the playhead 3/4 of the way along the page */
5105 l = frame - 3 * current_page_samples() / 4;
5113 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5119 Editor::super_rapid_screen_update ()
5121 if (!_session || !_session->engine().running()) {
5125 /* METERING / MIXER STRIPS */
5127 /* update track meters, if required */
5128 if (is_mapped() && meters_running) {
5129 RouteTimeAxisView* rtv;
5130 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5131 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5132 rtv->fast_update ();
5137 /* and any current mixer strip */
5138 if (current_mixer_strip) {
5139 current_mixer_strip->fast_update ();
5142 /* PLAYHEAD AND VIEWPORT */
5144 framepos_t const frame = _session->audible_frame();
5146 /* There are a few reasons why we might not update the playhead / viewport stuff:
5148 * 1. we don't update things when there's a pending locate request, otherwise
5149 * when the editor requests a locate there is a chance that this method
5150 * will move the playhead before the locate request is processed, causing
5152 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5153 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5156 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5158 last_update_frame = frame;
5160 if (!_dragging_playhead) {
5161 playhead_cursor->set_position (frame);
5164 if (!_stationary_playhead) {
5166 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5167 /* We only do this if we aren't already
5168 handling a visual change (ie if
5169 pending_visual_change.being_handled is
5170 false) so that these requests don't stack
5171 up there are too many of them to handle in
5174 reset_x_origin_to_follow_playhead ();
5179 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5183 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5184 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5185 if (target <= 0.0) {
5188 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5189 target = (target * 0.15) + (current * 0.85);
5195 set_horizontal_position (current);
5204 Editor::session_going_away ()
5206 _have_idled = false;
5208 _session_connections.drop_connections ();
5210 super_rapid_screen_update_connection.disconnect ();
5212 selection->clear ();
5213 cut_buffer->clear ();
5215 clicked_regionview = 0;
5216 clicked_axisview = 0;
5217 clicked_routeview = 0;
5218 entered_regionview = 0;
5220 last_update_frame = 0;
5223 playhead_cursor->hide ();
5225 /* rip everything out of the list displays */
5229 _route_groups->clear ();
5231 /* do this first so that deleting a track doesn't reset cms to null
5232 and thus cause a leak.
5235 if (current_mixer_strip) {
5236 if (current_mixer_strip->get_parent() != 0) {
5237 global_hpacker.remove (*current_mixer_strip);
5239 delete current_mixer_strip;
5240 current_mixer_strip = 0;
5243 /* delete all trackviews */
5245 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5248 track_views.clear ();
5250 zoom_range_clock->set_session (0);
5251 nudge_clock->set_session (0);
5253 editor_list_button.set_active(false);
5254 editor_list_button.set_sensitive(false);
5256 /* clear tempo/meter rulers */
5257 remove_metric_marks ();
5259 clear_marker_display ();
5261 stop_step_editing ();
5263 /* get rid of any existing editor mixer strip */
5265 WindowTitle title(Glib::get_application_name());
5266 title += _("Editor");
5268 set_title (title.get_string());
5270 SessionHandlePtr::session_going_away ();
5275 Editor::show_editor_list (bool yn)
5278 _the_notebook.show ();
5280 _the_notebook.hide ();
5285 Editor::change_region_layering_order (bool from_context_menu)
5287 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5289 if (!clicked_routeview) {
5290 if (layering_order_editor) {
5291 layering_order_editor->hide ();
5296 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5302 boost::shared_ptr<Playlist> pl = track->playlist();
5308 if (layering_order_editor == 0) {
5309 layering_order_editor = new RegionLayeringOrderEditor (*this);
5312 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5313 layering_order_editor->maybe_present ();
5317 Editor::update_region_layering_order_editor ()
5319 if (layering_order_editor && layering_order_editor->is_visible ()) {
5320 change_region_layering_order (true);
5325 Editor::setup_fade_images ()
5327 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5328 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5329 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5330 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5331 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5333 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5334 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5335 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5336 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5337 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5339 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5340 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5341 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5342 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5343 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5345 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5346 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5347 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5348 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5349 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5353 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5355 Editor::action_menu_item (std::string const & name)
5357 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5360 return *manage (a->create_menu_item ());
5364 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5366 EventBox* b = manage (new EventBox);
5367 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5368 Label* l = manage (new Label (name));
5372 _the_notebook.append_page (widget, *b);
5376 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5378 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5379 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5382 if (ev->type == GDK_2BUTTON_PRESS) {
5384 /* double-click on a notebook tab shrinks or expands the notebook */
5386 if (_notebook_shrunk) {
5387 if (pre_notebook_shrink_pane_width) {
5388 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5390 _notebook_shrunk = false;
5392 pre_notebook_shrink_pane_width = edit_pane.get_position();
5394 /* this expands the LHS of the edit pane to cover the notebook
5395 PAGE but leaves the tabs visible.
5397 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5398 _notebook_shrunk = true;
5406 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5408 using namespace Menu_Helpers;
5410 MenuList& items = _control_point_context_menu.items ();
5413 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5414 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5415 if (!can_remove_control_point (item)) {
5416 items.back().set_sensitive (false);
5419 _control_point_context_menu.popup (event->button.button, event->button.time);
5423 Editor::zoom_vertical_modifier_released()
5425 _stepping_axis_view = 0;
5429 Editor::ui_parameter_changed (string parameter)
5431 if (parameter == "icon-set") {
5432 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());