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"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 pane_size_watcher (Paned* pane)
217 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
221 Quartz: impossible to access
223 so stop that by preventing it from ever getting too narrow. 35
224 pixels is basically a rough guess at the tab width.
229 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
231 gint pos = pane->get_position ();
233 if (pos > max_width_of_lhs) {
234 pane->set_position (max_width_of_lhs);
239 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241 /* time display buttons */
242 , minsec_label (_("Mins:Secs"))
243 , bbt_label (_("Bars:Beats"))
244 , timecode_label (_("Timecode"))
245 , samples_label (_("Samples"))
246 , tempo_label (_("Tempo"))
247 , meter_label (_("Meter"))
248 , mark_label (_("Location Markers"))
249 , range_mark_label (_("Range Markers"))
250 , transport_mark_label (_("Loop/Punch Ranges"))
251 , cd_mark_label (_("CD Markers"))
252 , videotl_label (_("Video Timeline"))
253 , edit_packer (4, 4, true)
255 /* the values here don't matter: layout widgets
256 reset them as needed.
259 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 , horizontal_adjustment (0.0, 0.0, 1e16)
261 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
263 , controls_layout (unused_adjustment, vertical_adjustment)
265 /* tool bar related */
267 , toolbar_selection_clock_table (2,3)
268 , _mouse_mode_tearoff (0)
269 , automation_mode_button (_("mode"))
273 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
278 , meters_running(false)
279 , _pending_locate_request (false)
280 , _pending_initial_locate (false)
281 , _last_cut_copy_source_track (0)
283 , _region_selection_change_updates_region_list (true)
284 , _following_mixer_selection (false)
285 , _control_point_toggled_on_press (false)
286 , _stepping_axis_view (0)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_control_point = 0;
303 last_update_frame = 0;
304 pre_press_cursor = 0;
305 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 build_edit_mode_menu();
321 build_zoom_focus_menu();
322 build_track_count_menu();
323 build_snap_mode_menu();
324 build_snap_type_menu();
325 build_edit_point_menu();
327 snap_threshold = 5.0;
328 bbt_beat_subdivision = 4;
329 _visible_canvas_width = 0;
330 _visible_canvas_height = 0;
331 autoscroll_horizontal_allowed = false;
332 autoscroll_vertical_allowed = false;
337 current_interthread_info = 0;
338 _show_measures = true;
340 show_gain_after_trim = false;
342 have_pending_keyboard_selection = false;
343 _follow_playhead = true;
344 _stationary_playhead = false;
345 editor_ruler_menu = 0;
346 no_ruler_shown_update = false;
348 range_marker_menu = 0;
349 marker_menu_item = 0;
350 tempo_or_meter_marker_menu = 0;
351 transport_marker_menu = 0;
352 new_transport_marker_menu = 0;
353 editor_mixer_strip_width = Wide;
354 show_editor_mixer_when_tracks_arrive = false;
355 region_edit_menu_split_multichannel_item = 0;
356 region_edit_menu_split_item = 0;
359 current_stepping_trackview = 0;
361 entered_regionview = 0;
363 clear_entered_track = false;
366 button_release_can_deselect = true;
367 _dragging_playhead = false;
368 _dragging_edit_point = false;
369 select_new_marker = false;
371 layering_order_editor = 0;
372 no_save_visual = false;
374 within_track_canvas = false;
376 scrubbing_direction = 0;
380 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
381 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
382 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
383 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
384 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
386 zoom_focus = ZoomFocusLeft;
387 _edit_point = EditAtMouse;
388 _internal_editing = false;
389 current_canvas_cursor = 0;
390 _visible_track_count = 16;
392 samples_per_pixel = 2048; /* too early to use reset_zoom () */
394 _scroll_callbacks = 0;
396 bbt_label.set_name ("EditorRulerLabel");
397 bbt_label.set_size_request (-1, (int)timebar_height);
398 bbt_label.set_alignment (1.0, 0.5);
399 bbt_label.set_padding (5,0);
401 bbt_label.set_no_show_all();
402 minsec_label.set_name ("EditorRulerLabel");
403 minsec_label.set_size_request (-1, (int)timebar_height);
404 minsec_label.set_alignment (1.0, 0.5);
405 minsec_label.set_padding (5,0);
406 minsec_label.hide ();
407 minsec_label.set_no_show_all();
408 timecode_label.set_name ("EditorRulerLabel");
409 timecode_label.set_size_request (-1, (int)timebar_height);
410 timecode_label.set_alignment (1.0, 0.5);
411 timecode_label.set_padding (5,0);
412 timecode_label.hide ();
413 timecode_label.set_no_show_all();
414 samples_label.set_name ("EditorRulerLabel");
415 samples_label.set_size_request (-1, (int)timebar_height);
416 samples_label.set_alignment (1.0, 0.5);
417 samples_label.set_padding (5,0);
418 samples_label.hide ();
419 samples_label.set_no_show_all();
421 tempo_label.set_name ("EditorRulerLabel");
422 tempo_label.set_size_request (-1, (int)timebar_height);
423 tempo_label.set_alignment (1.0, 0.5);
424 tempo_label.set_padding (5,0);
426 tempo_label.set_no_show_all();
428 meter_label.set_name ("EditorRulerLabel");
429 meter_label.set_size_request (-1, (int)timebar_height);
430 meter_label.set_alignment (1.0, 0.5);
431 meter_label.set_padding (5,0);
433 meter_label.set_no_show_all();
435 if (Profile->get_trx()) {
436 mark_label.set_text (_("Markers"));
438 mark_label.set_name ("EditorRulerLabel");
439 mark_label.set_size_request (-1, (int)timebar_height);
440 mark_label.set_alignment (1.0, 0.5);
441 mark_label.set_padding (5,0);
443 mark_label.set_no_show_all();
445 cd_mark_label.set_name ("EditorRulerLabel");
446 cd_mark_label.set_size_request (-1, (int)timebar_height);
447 cd_mark_label.set_alignment (1.0, 0.5);
448 cd_mark_label.set_padding (5,0);
449 cd_mark_label.hide();
450 cd_mark_label.set_no_show_all();
452 videotl_bar_height = 4;
453 videotl_label.set_name ("EditorRulerLabel");
454 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
455 videotl_label.set_alignment (1.0, 0.5);
456 videotl_label.set_padding (5,0);
457 videotl_label.hide();
458 videotl_label.set_no_show_all();
460 range_mark_label.set_name ("EditorRulerLabel");
461 range_mark_label.set_size_request (-1, (int)timebar_height);
462 range_mark_label.set_alignment (1.0, 0.5);
463 range_mark_label.set_padding (5,0);
464 range_mark_label.hide();
465 range_mark_label.set_no_show_all();
467 transport_mark_label.set_name ("EditorRulerLabel");
468 transport_mark_label.set_size_request (-1, (int)timebar_height);
469 transport_mark_label.set_alignment (1.0, 0.5);
470 transport_mark_label.set_padding (5,0);
471 transport_mark_label.hide();
472 transport_mark_label.set_no_show_all();
474 initialize_canvas ();
476 _summary = new EditorSummary (this);
478 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
479 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
481 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
483 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
484 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
486 edit_controls_vbox.set_spacing (0);
487 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
488 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
490 HBox* h = manage (new HBox);
491 _group_tabs = new EditorGroupTabs (this);
492 if (!ARDOUR::Profile->get_trx()) {
493 h->pack_start (*_group_tabs, PACK_SHRINK);
495 h->pack_start (edit_controls_vbox);
496 controls_layout.add (*h);
498 controls_layout.set_name ("EditControlsBase");
499 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
500 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
501 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
503 _cursors = new MouseCursors;
504 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
505 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
507 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
509 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
510 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
511 pad_line_1->set_outline_color (0xFF0000FF);
517 edit_packer.set_col_spacings (0);
518 edit_packer.set_row_spacings (0);
519 edit_packer.set_homogeneous (false);
520 edit_packer.set_border_width (0);
521 edit_packer.set_name ("EditorWindow");
523 time_bars_event_box.add (time_bars_vbox);
524 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
525 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
527 /* labels for the time bars */
528 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
530 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
532 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 if (!ARDOUR::Profile->get_trx()) {
598 editor_summary_pane.pack2 (_summary_hbox);
601 edit_pane.pack1 (editor_summary_pane, true, true);
602 if (!ARDOUR::Profile->get_trx()) {
603 edit_pane.pack2 (_the_notebook, false, true);
606 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
608 /* XXX: editor_summary_pane might need similar to the edit_pane */
610 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
612 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
615 top_hbox.pack_start (toolbar_frame);
617 HBox *hbox = manage (new HBox);
618 hbox->pack_start (edit_pane, true, true);
620 global_vpacker.pack_start (top_hbox, false, false);
621 global_vpacker.pack_start (*hbox, true, true);
623 global_hpacker.pack_start (global_vpacker, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager->get_accel_group());
628 status_bar_hpacker.show ();
630 vpacker.pack_end (status_bar_hpacker, false, false);
631 vpacker.pack_end (global_hpacker, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
636 /* when we start using our own keybinding system for the editor, this
637 * will be uncommented
643 set_zoom_focus (zoom_focus);
644 set_visible_track_count (_visible_track_count);
645 _snap_type = SnapToBeat;
646 set_snap_to (_snap_type);
647 _snap_mode = SnapOff;
648 set_snap_mode (_snap_mode);
649 set_mouse_mode (MouseObject, true);
650 pre_internal_mouse_mode = MouseObject;
651 pre_internal_snap_type = _snap_type;
652 pre_internal_snap_mode = _snap_mode;
653 internal_snap_type = _snap_type;
654 internal_snap_mode = _snap_mode;
655 set_edit_point_preference (EditAtMouse, true);
657 _playlist_selector = new PlaylistSelector();
658 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
660 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
664 nudge_forward_button.set_name ("nudge button");
665 // nudge_forward_button.add_elements (ArdourButton::Inset);
666 nudge_forward_button.set_image(::get_icon("nudge_right"));
668 nudge_backward_button.set_name ("nudge button");
669 // nudge_backward_button.add_elements (ArdourButton::Inset);
670 nudge_backward_button.set_image(::get_icon("nudge_left"));
672 fade_context_menu.set_name ("ArdourContextMenu");
674 /* icons, titles, WM stuff */
676 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
677 Glib::RefPtr<Gdk::Pixbuf> icon;
679 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
686 window_icons.push_back (icon);
688 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
689 window_icons.push_back (icon);
691 if (!window_icons.empty()) {
692 // set_icon_list (window_icons);
693 set_default_icon_list (window_icons);
696 WindowTitle title(Glib::get_application_name());
697 title += _("Editor");
698 set_title (title.get_string());
699 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
702 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
704 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
705 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
707 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
709 /* allow external control surfaces/protocols to do various things */
711 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
712 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
713 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
714 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
715 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
716 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
717 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
718 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
719 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
720 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
721 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
722 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
723 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
724 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
726 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
727 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
728 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
729 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
730 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
732 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
734 /* problematic: has to return a value and thus cannot be x-thread */
736 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
738 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
739 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
741 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
743 _ignore_region_action = false;
744 _last_region_menu_was_main = false;
745 _popup_region_menu_item = 0;
747 _ignore_follow_edits = false;
749 _show_marker_lines = false;
751 /* Button bindings */
753 button_bindings = new Bindings;
755 XMLNode* node = button_settings();
757 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
758 button_bindings->load (**i);
764 /* grab current parameter state */
765 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
766 ARDOUR_UI::config()->map_parameters (pc);
768 setup_fade_images ();
775 delete button_bindings;
777 delete _route_groups;
778 delete _track_canvas_viewport;
783 Editor::button_settings () const
785 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
786 XMLNode* node = find_named_node (*settings, X_("Buttons"));
789 node = new XMLNode (X_("Buttons"));
796 Editor::add_toplevel_controls (Container& cont)
798 vpacker.pack_start (cont, false, false);
803 Editor::get_smart_mode () const
805 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
809 Editor::catch_vanishing_regionview (RegionView *rv)
811 /* note: the selection will take care of the vanishing
812 audioregionview by itself.
815 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
819 if (clicked_regionview == rv) {
820 clicked_regionview = 0;
823 if (entered_regionview == rv) {
824 set_entered_regionview (0);
827 if (!_all_region_actions_sensitized) {
828 sensitize_all_region_actions (true);
833 Editor::set_entered_regionview (RegionView* rv)
835 if (rv == entered_regionview) {
839 if (entered_regionview) {
840 entered_regionview->exited ();
843 entered_regionview = rv;
845 if (entered_regionview != 0) {
846 entered_regionview->entered (internal_editing ());
849 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
850 /* This RegionView entry might have changed what region actions
851 are allowed, so sensitize them all in case a key is pressed.
853 sensitize_all_region_actions (true);
858 Editor::set_entered_track (TimeAxisView* tav)
861 entered_track->exited ();
867 entered_track->entered ();
872 Editor::show_window ()
874 if (!is_visible ()) {
877 /* XXX: this is a bit unfortunate; it would probably
878 be nicer if we could just call show () above rather
879 than needing the show_all ()
882 /* re-hide stuff if necessary */
883 editor_list_button_toggled ();
884 parameter_changed ("show-summary");
885 parameter_changed ("show-group-tabs");
886 parameter_changed ("show-zoom-tools");
888 /* now reset all audio_time_axis heights, because widgets might need
894 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
895 tv = (static_cast<TimeAxisView*>(*i));
899 if (current_mixer_strip) {
900 current_mixer_strip->hide_things ();
901 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
909 Editor::instant_save ()
911 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
916 _session->add_instant_xml(get_state());
918 Config->add_instant_xml(get_state());
923 Editor::control_vertical_zoom_in_all ()
925 tav_zoom_smooth (false, true);
929 Editor::control_vertical_zoom_out_all ()
931 tav_zoom_smooth (true, true);
935 Editor::control_vertical_zoom_in_selected ()
937 tav_zoom_smooth (false, false);
941 Editor::control_vertical_zoom_out_selected ()
943 tav_zoom_smooth (true, false);
947 Editor::control_view (uint32_t view)
949 goto_visual_state (view);
953 Editor::control_unselect ()
955 selection->clear_tracks ();
959 Editor::control_select (uint32_t rid, Selection::Operation op)
961 /* handles the (static) signal from the ControlProtocol class that
962 * requests setting the selected track to a given RID
969 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
975 TimeAxisView* tav = axis_view_from_route (r);
980 selection->add (tav);
982 case Selection::Toggle:
983 selection->toggle (tav);
985 case Selection::Extend:
988 selection->set (tav);
992 selection->clear_tracks ();
997 Editor::control_step_tracks_up ()
999 scroll_tracks_up_line ();
1003 Editor::control_step_tracks_down ()
1005 scroll_tracks_down_line ();
1009 Editor::control_scroll (float fraction)
1011 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1017 double step = fraction * current_page_samples();
1020 _control_scroll_target is an optional<T>
1022 it acts like a pointer to an framepos_t, with
1023 a operator conversion to boolean to check
1024 that it has a value could possibly use
1025 playhead_cursor->current_frame to store the
1026 value and a boolean in the class to know
1027 when it's out of date
1030 if (!_control_scroll_target) {
1031 _control_scroll_target = _session->transport_frame();
1032 _dragging_playhead = true;
1035 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1036 *_control_scroll_target = 0;
1037 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1038 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1040 *_control_scroll_target += (framepos_t) floor (step);
1043 /* move visuals, we'll catch up with it later */
1045 playhead_cursor->set_position (*_control_scroll_target);
1046 UpdateAllTransportClocks (*_control_scroll_target);
1048 if (*_control_scroll_target > (current_page_samples() / 2)) {
1049 /* try to center PH in window */
1050 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1056 Now we do a timeout to actually bring the session to the right place
1057 according to the playhead. This is to avoid reading disk buffers on every
1058 call to control_scroll, which is driven by ScrollTimeline and therefore
1059 probably by a control surface wheel which can generate lots of events.
1061 /* cancel the existing timeout */
1063 control_scroll_connection.disconnect ();
1065 /* add the next timeout */
1067 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1071 Editor::deferred_control_scroll (framepos_t /*target*/)
1073 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1074 // reset for next stream
1075 _control_scroll_target = boost::none;
1076 _dragging_playhead = false;
1081 Editor::access_action (std::string action_group, std::string action_item)
1087 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1090 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1098 Editor::on_realize ()
1100 Window::on_realize ();
1103 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1104 start_lock_event_timing ();
1107 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1111 Editor::start_lock_event_timing ()
1113 /* check if we should lock the GUI every 30 seconds */
1115 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1119 Editor::generic_event_handler (GdkEvent* ev)
1122 case GDK_BUTTON_PRESS:
1123 case GDK_BUTTON_RELEASE:
1124 case GDK_MOTION_NOTIFY:
1126 case GDK_KEY_RELEASE:
1127 gettimeofday (&last_event_time, 0);
1136 Editor::lock_timeout_callback ()
1138 struct timeval now, delta;
1140 gettimeofday (&now, 0);
1142 timersub (&now, &last_event_time, &delta);
1144 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1146 /* don't call again. Returning false will effectively
1147 disconnect us from the timer callback.
1149 unlock() will call start_lock_event_timing() to get things
1159 Editor::map_position_change (framepos_t frame)
1161 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1163 if (_session == 0) {
1167 if (_follow_playhead) {
1168 center_screen (frame);
1171 playhead_cursor->set_position (frame);
1175 Editor::center_screen (framepos_t frame)
1177 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1179 /* if we're off the page, then scroll.
1182 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1183 center_screen_internal (frame, page);
1188 Editor::center_screen_internal (framepos_t frame, float page)
1193 frame -= (framepos_t) page;
1198 reset_x_origin (frame);
1203 Editor::update_title ()
1205 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1208 bool dirty = _session->dirty();
1210 string session_name;
1212 if (_session->snap_name() != _session->name()) {
1213 session_name = _session->snap_name();
1215 session_name = _session->name();
1219 session_name = "*" + session_name;
1222 WindowTitle title(session_name);
1223 title += Glib::get_application_name();
1224 set_title (title.get_string());
1226 /* ::session_going_away() will have taken care of it */
1231 Editor::set_session (Session *t)
1233 SessionHandlePtr::set_session (t);
1239 _playlist_selector->set_session (_session);
1240 nudge_clock->set_session (_session);
1241 _summary->set_session (_session);
1242 _group_tabs->set_session (_session);
1243 _route_groups->set_session (_session);
1244 _regions->set_session (_session);
1245 _snapshots->set_session (_session);
1246 _routes->set_session (_session);
1247 _locations->set_session (_session);
1249 if (rhythm_ferret) {
1250 rhythm_ferret->set_session (_session);
1253 if (analysis_window) {
1254 analysis_window->set_session (_session);
1258 sfbrowser->set_session (_session);
1261 compute_fixed_ruler_scale ();
1263 /* Make sure we have auto loop and auto punch ranges */
1265 Location* loc = _session->locations()->auto_loop_location();
1267 loc->set_name (_("Loop"));
1270 loc = _session->locations()->auto_punch_location();
1273 loc->set_name (_("Punch"));
1276 refresh_location_display ();
1278 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1279 the selected Marker; this needs the LocationMarker list to be available.
1281 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1282 set_state (*node, Stateful::loading_state_version);
1284 /* catch up with the playhead */
1286 _session->request_locate (playhead_cursor->current_frame ());
1287 _pending_initial_locate = true;
1291 /* These signals can all be emitted by a non-GUI thread. Therefore the
1292 handlers for them must not attempt to directly interact with the GUI,
1293 but use PBD::Signal<T>::connect() which accepts an event loop
1294 ("context") where the handler will be asked to run.
1297 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1298 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1299 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1300 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1301 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1302 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1303 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1304 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1305 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1306 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1307 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1308 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1309 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1310 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1312 playhead_cursor->show ();
1314 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1315 Config->map_parameters (pc);
1316 _session->config.map_parameters (pc);
1318 restore_ruler_visibility ();
1319 //tempo_map_changed (PropertyChange (0));
1320 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1322 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1323 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1326 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1327 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1330 switch (_snap_type) {
1331 case SnapToRegionStart:
1332 case SnapToRegionEnd:
1333 case SnapToRegionSync:
1334 case SnapToRegionBoundary:
1335 build_region_boundary_cache ();
1342 /* register for undo history */
1343 _session->register_with_memento_command_factory(id(), this);
1345 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1347 start_updating_meters ();
1351 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1353 if (a->get_name() == "RegionMenu") {
1354 /* When the main menu's region menu is opened, we setup the actions so that they look right
1355 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1356 so we resensitize all region actions when the entered regionview or the region selection
1357 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1358 happens after the region context menu is opened. So we set a flag here, too.
1362 sensitize_the_right_region_actions ();
1363 _last_region_menu_was_main = true;
1368 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1370 using namespace Menu_Helpers;
1372 void (Editor::*emf)(FadeShape);
1373 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1376 images = &_xfade_in_images;
1377 emf = &Editor::set_fade_in_shape;
1379 images = &_xfade_out_images;
1380 emf = &Editor::set_fade_out_shape;
1385 _("Linear (for highly correlated material)"),
1386 *(*images)[FadeLinear],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1391 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 _("Constant power"),
1396 *(*images)[FadeConstantPower],
1397 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 *(*images)[FadeSymmetric],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1410 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1415 *(*images)[FadeSlow],
1416 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1424 *(*images)[FadeFast],
1425 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1428 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1431 /** Pop up a context menu for when the user clicks on a start crossfade */
1433 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1435 using namespace Menu_Helpers;
1436 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1439 MenuList& items (xfade_in_context_menu.items());
1442 if (arv->audio_region()->fade_in_active()) {
1443 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1445 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1448 items.push_back (SeparatorElem());
1449 fill_xfade_menu (items, true);
1451 xfade_in_context_menu.popup (button, time);
1454 /** Pop up a context menu for when the user clicks on an end crossfade */
1456 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1458 using namespace Menu_Helpers;
1459 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1462 MenuList& items (xfade_out_context_menu.items());
1465 if (arv->audio_region()->fade_out_active()) {
1466 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1468 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1471 items.push_back (SeparatorElem());
1472 fill_xfade_menu (items, false);
1474 xfade_out_context_menu.popup (button, time);
1478 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1480 using namespace Menu_Helpers;
1481 Menu* (Editor::*build_menu_function)();
1484 switch (item_type) {
1486 case RegionViewName:
1487 case RegionViewNameHighlight:
1488 case LeftFrameHandle:
1489 case RightFrameHandle:
1490 if (with_selection) {
1491 build_menu_function = &Editor::build_track_selection_context_menu;
1493 build_menu_function = &Editor::build_track_region_context_menu;
1498 if (with_selection) {
1499 build_menu_function = &Editor::build_track_selection_context_menu;
1501 build_menu_function = &Editor::build_track_context_menu;
1506 if (clicked_routeview->track()) {
1507 build_menu_function = &Editor::build_track_context_menu;
1509 build_menu_function = &Editor::build_track_bus_context_menu;
1514 /* probably shouldn't happen but if it does, we don't care */
1518 menu = (this->*build_menu_function)();
1519 menu->set_name ("ArdourContextMenu");
1521 /* now handle specific situations */
1523 switch (item_type) {
1525 case RegionViewName:
1526 case RegionViewNameHighlight:
1527 case LeftFrameHandle:
1528 case RightFrameHandle:
1529 if (!with_selection) {
1530 if (region_edit_menu_split_item) {
1531 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1532 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1534 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1537 if (region_edit_menu_split_multichannel_item) {
1538 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1539 region_edit_menu_split_multichannel_item->set_sensitive (true);
1541 region_edit_menu_split_multichannel_item->set_sensitive (false);
1554 /* probably shouldn't happen but if it does, we don't care */
1558 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1560 /* Bounce to disk */
1562 using namespace Menu_Helpers;
1563 MenuList& edit_items = menu->items();
1565 edit_items.push_back (SeparatorElem());
1567 switch (clicked_routeview->audio_track()->freeze_state()) {
1568 case AudioTrack::NoFreeze:
1569 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1572 case AudioTrack::Frozen:
1573 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1576 case AudioTrack::UnFrozen:
1577 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1583 if (item_type == StreamItem && clicked_routeview) {
1584 clicked_routeview->build_underlay_menu(menu);
1587 /* When the region menu is opened, we setup the actions so that they look right
1590 sensitize_the_right_region_actions ();
1591 _last_region_menu_was_main = false;
1593 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1594 menu->popup (button, time);
1598 Editor::build_track_context_menu ()
1600 using namespace Menu_Helpers;
1602 MenuList& edit_items = track_context_menu.items();
1605 add_dstream_context_items (edit_items);
1606 return &track_context_menu;
1610 Editor::build_track_bus_context_menu ()
1612 using namespace Menu_Helpers;
1614 MenuList& edit_items = track_context_menu.items();
1617 add_bus_context_items (edit_items);
1618 return &track_context_menu;
1622 Editor::build_track_region_context_menu ()
1624 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_region_context_menu.items();
1628 /* we've just cleared the track region context menu, so the menu that these
1629 two items were on will have disappeared; stop them dangling.
1631 region_edit_menu_split_item = 0;
1632 region_edit_menu_split_multichannel_item = 0;
1634 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1637 boost::shared_ptr<Track> tr;
1638 boost::shared_ptr<Playlist> pl;
1640 if ((tr = rtv->track())) {
1641 add_region_context_items (edit_items, tr);
1645 add_dstream_context_items (edit_items);
1647 return &track_region_context_menu;
1651 Editor::analyze_region_selection ()
1653 if (analysis_window == 0) {
1654 analysis_window = new AnalysisWindow();
1657 analysis_window->set_session(_session);
1659 analysis_window->show_all();
1662 analysis_window->set_regionmode();
1663 analysis_window->analyze();
1665 analysis_window->present();
1669 Editor::analyze_range_selection()
1671 if (analysis_window == 0) {
1672 analysis_window = new AnalysisWindow();
1675 analysis_window->set_session(_session);
1677 analysis_window->show_all();
1680 analysis_window->set_rangemode();
1681 analysis_window->analyze();
1683 analysis_window->present();
1687 Editor::build_track_selection_context_menu ()
1689 using namespace Menu_Helpers;
1690 MenuList& edit_items = track_selection_context_menu.items();
1691 edit_items.clear ();
1693 add_selection_context_items (edit_items);
1694 // edit_items.push_back (SeparatorElem());
1695 // add_dstream_context_items (edit_items);
1697 return &track_selection_context_menu;
1701 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1703 using namespace Menu_Helpers;
1705 /* OK, stick the region submenu at the top of the list, and then add
1709 RegionSelection rs = get_regions_from_selection_and_entered ();
1711 string::size_type pos = 0;
1712 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1714 /* we have to hack up the region name because "_" has a special
1715 meaning for menu titles.
1718 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1719 menu_item_name.replace (pos, 1, "__");
1723 if (_popup_region_menu_item == 0) {
1724 _popup_region_menu_item = new MenuItem (menu_item_name);
1725 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1726 _popup_region_menu_item->show ();
1728 _popup_region_menu_item->set_label (menu_item_name);
1731 const framepos_t position = get_preferred_edit_position (false, true);
1733 edit_items.push_back (*_popup_region_menu_item);
1734 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1735 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1737 edit_items.push_back (SeparatorElem());
1740 /** Add context menu items relevant to selection ranges.
1741 * @param edit_items List to add the items to.
1744 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1746 using namespace Menu_Helpers;
1748 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1749 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1751 edit_items.push_back (SeparatorElem());
1752 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1754 edit_items.push_back (SeparatorElem());
1756 edit_items.push_back (
1758 _("Move Range Start to Previous Region Boundary"),
1759 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1763 edit_items.push_back (
1765 _("Move Range Start to Next Region Boundary"),
1766 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1770 edit_items.push_back (
1772 _("Move Range End to Previous Region Boundary"),
1773 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1777 edit_items.push_back (
1779 _("Move Range End to Next Region Boundary"),
1780 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1784 edit_items.push_back (SeparatorElem());
1785 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1786 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1788 edit_items.push_back (SeparatorElem());
1789 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1791 edit_items.push_back (SeparatorElem());
1792 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1793 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1795 edit_items.push_back (SeparatorElem());
1796 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1798 edit_items.push_back (SeparatorElem());
1799 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1800 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1801 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1805 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1806 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1807 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1808 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1809 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1810 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1816 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1818 using namespace Menu_Helpers;
1822 Menu *play_menu = manage (new Menu);
1823 MenuList& play_items = play_menu->items();
1824 play_menu->set_name ("ArdourContextMenu");
1826 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1827 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1828 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1829 play_items.push_back (SeparatorElem());
1830 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1832 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1836 Menu *select_menu = manage (new Menu);
1837 MenuList& select_items = select_menu->items();
1838 select_menu->set_name ("ArdourContextMenu");
1840 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1841 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1842 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1843 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1844 select_items.push_back (SeparatorElem());
1845 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1846 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1847 select_items.push_back (SeparatorElem());
1848 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1849 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1850 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1851 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1852 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1853 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1854 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1856 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1860 Menu *cutnpaste_menu = manage (new Menu);
1861 MenuList& cutnpaste_items = cutnpaste_menu->items();
1862 cutnpaste_menu->set_name ("ArdourContextMenu");
1864 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1865 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1866 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1868 cutnpaste_items.push_back (SeparatorElem());
1870 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1871 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1873 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1875 /* Adding new material */
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1879 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1883 Menu *nudge_menu = manage (new Menu());
1884 MenuList& nudge_items = nudge_menu->items();
1885 nudge_menu->set_name ("ArdourContextMenu");
1887 edit_items.push_back (SeparatorElem());
1888 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1889 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1890 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1891 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1893 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1897 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1899 using namespace Menu_Helpers;
1903 Menu *play_menu = manage (new Menu);
1904 MenuList& play_items = play_menu->items();
1905 play_menu->set_name ("ArdourContextMenu");
1907 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1908 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1909 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1913 Menu *select_menu = manage (new Menu);
1914 MenuList& select_items = select_menu->items();
1915 select_menu->set_name ("ArdourContextMenu");
1917 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1918 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1919 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1920 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1921 select_items.push_back (SeparatorElem());
1922 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1923 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1924 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1925 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1927 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1931 Menu *cutnpaste_menu = manage (new Menu);
1932 MenuList& cutnpaste_items = cutnpaste_menu->items();
1933 cutnpaste_menu->set_name ("ArdourContextMenu");
1935 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1936 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1939 Menu *nudge_menu = manage (new Menu());
1940 MenuList& nudge_items = nudge_menu->items();
1941 nudge_menu->set_name ("ArdourContextMenu");
1943 edit_items.push_back (SeparatorElem());
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1946 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1947 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1949 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1953 Editor::snap_type() const
1959 Editor::snap_mode() const
1965 Editor::set_snap_to (SnapType st)
1967 unsigned int snap_ind = (unsigned int)st;
1971 if (snap_ind > snap_type_strings.size() - 1) {
1973 _snap_type = (SnapType)snap_ind;
1976 string str = snap_type_strings[snap_ind];
1978 if (str != snap_type_selector.get_text()) {
1979 snap_type_selector.set_text (str);
1984 switch (_snap_type) {
1985 case SnapToBeatDiv128:
1986 case SnapToBeatDiv64:
1987 case SnapToBeatDiv32:
1988 case SnapToBeatDiv28:
1989 case SnapToBeatDiv24:
1990 case SnapToBeatDiv20:
1991 case SnapToBeatDiv16:
1992 case SnapToBeatDiv14:
1993 case SnapToBeatDiv12:
1994 case SnapToBeatDiv10:
1995 case SnapToBeatDiv8:
1996 case SnapToBeatDiv7:
1997 case SnapToBeatDiv6:
1998 case SnapToBeatDiv5:
1999 case SnapToBeatDiv4:
2000 case SnapToBeatDiv3:
2001 case SnapToBeatDiv2: {
2002 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2003 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2005 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2006 current_bbt_points_begin, current_bbt_points_end);
2007 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2008 current_bbt_points_begin, current_bbt_points_end);
2009 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2013 case SnapToRegionStart:
2014 case SnapToRegionEnd:
2015 case SnapToRegionSync:
2016 case SnapToRegionBoundary:
2017 build_region_boundary_cache ();
2025 SnapChanged (); /* EMIT SIGNAL */
2029 Editor::set_snap_mode (SnapMode mode)
2031 string str = snap_mode_strings[(int)mode];
2033 if (_internal_editing) {
2034 internal_snap_mode = mode;
2036 pre_internal_snap_mode = mode;
2041 if (str != snap_mode_selector.get_text ()) {
2042 snap_mode_selector.set_text (str);
2048 Editor::set_edit_point_preference (EditPoint ep, bool force)
2050 bool changed = (_edit_point != ep);
2053 string str = edit_point_strings[(int)ep];
2055 if (str != edit_point_selector.get_text ()) {
2056 edit_point_selector.set_text (str);
2059 reset_canvas_cursor ();
2061 if (!force && !changed) {
2065 const char* action=NULL;
2067 switch (_edit_point) {
2068 case EditAtPlayhead:
2069 action = "edit-at-playhead";
2071 case EditAtSelectedMarker:
2072 action = "edit-at-marker";
2075 action = "edit-at-mouse";
2079 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2081 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2085 bool in_track_canvas;
2087 if (!mouse_frame (foo, in_track_canvas)) {
2088 in_track_canvas = false;
2091 reset_canvas_action_sensitivity (in_track_canvas);
2097 Editor::set_state (const XMLNode& node, int /*version*/)
2099 const XMLProperty* prop;
2106 g.base_width = default_width;
2107 g.base_height = default_height;
2111 if ((geometry = find_named_node (node, "geometry")) != 0) {
2115 if ((prop = geometry->property("x_size")) == 0) {
2116 prop = geometry->property ("x-size");
2119 g.base_width = atoi(prop->value());
2121 if ((prop = geometry->property("y_size")) == 0) {
2122 prop = geometry->property ("y-size");
2125 g.base_height = atoi(prop->value());
2128 if ((prop = geometry->property ("x_pos")) == 0) {
2129 prop = geometry->property ("x-pos");
2132 x = atoi (prop->value());
2135 if ((prop = geometry->property ("y_pos")) == 0) {
2136 prop = geometry->property ("y-pos");
2139 y = atoi (prop->value());
2143 set_default_size (g.base_width, g.base_height);
2146 if (_session && (prop = node.property ("playhead"))) {
2148 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2149 playhead_cursor->set_position (pos);
2151 playhead_cursor->set_position (0);
2154 if ((prop = node.property ("mixer-width"))) {
2155 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2158 if ((prop = node.property ("zoom-focus"))) {
2159 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2162 if ((prop = node.property ("zoom"))) {
2163 /* older versions of ardour used floating point samples_per_pixel */
2164 double f = PBD::atof (prop->value());
2165 reset_zoom (llrintf (f));
2167 reset_zoom (samples_per_pixel);
2170 if ((prop = node.property ("visible-track-count"))) {
2171 set_visible_track_count (PBD::atoi (prop->value()));
2174 if ((prop = node.property ("snap-to"))) {
2175 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2178 if ((prop = node.property ("snap-mode"))) {
2179 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2182 if ((prop = node.property ("internal-snap-to"))) {
2183 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2186 if ((prop = node.property ("internal-snap-mode"))) {
2187 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2190 if ((prop = node.property ("pre-internal-snap-to"))) {
2191 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2195 if ((prop = node.property ("pre-internal-snap-mode"))) {
2196 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2199 if ((prop = node.property ("mouse-mode"))) {
2200 MouseMode m = str2mousemode(prop->value());
2201 set_mouse_mode (m, true);
2203 set_mouse_mode (MouseObject, true);
2206 if ((prop = node.property ("left-frame")) != 0) {
2208 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2212 reset_x_origin (pos);
2216 if ((prop = node.property ("y-origin")) != 0) {
2217 reset_y_origin (atof (prop->value ()));
2220 if ((prop = node.property ("internal-edit"))) {
2221 bool yn = string_is_affirmative (prop->value());
2222 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2224 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2225 tact->set_active (!yn);
2226 tact->set_active (yn);
2230 if ((prop = node.property ("join-object-range"))) {
2231 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2232 bool yn = string_is_affirmative (prop->value());
2234 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2235 tact->set_active (!yn);
2236 tact->set_active (yn);
2238 set_mouse_mode(mouse_mode, true);
2241 if ((prop = node.property ("edit-point"))) {
2242 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2245 if ((prop = node.property ("show-measures"))) {
2246 bool yn = string_is_affirmative (prop->value());
2247 _show_measures = yn;
2248 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2250 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2251 /* do it twice to force the change */
2252 tact->set_active (!yn);
2253 tact->set_active (yn);
2257 if ((prop = node.property ("follow-playhead"))) {
2258 bool yn = string_is_affirmative (prop->value());
2259 set_follow_playhead (yn);
2260 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2262 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2263 if (tact->get_active() != yn) {
2264 tact->set_active (yn);
2269 if ((prop = node.property ("stationary-playhead"))) {
2270 bool yn = string_is_affirmative (prop->value());
2271 set_stationary_playhead (yn);
2272 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2274 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2275 if (tact->get_active() != yn) {
2276 tact->set_active (yn);
2281 if ((prop = node.property ("region-list-sort-type"))) {
2282 RegionListSortType st;
2283 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2286 if ((prop = node.property ("show-editor-mixer"))) {
2288 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2291 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2292 bool yn = string_is_affirmative (prop->value());
2294 /* do it twice to force the change */
2296 tact->set_active (!yn);
2297 tact->set_active (yn);
2300 if ((prop = node.property ("show-editor-list"))) {
2302 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2305 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2306 bool yn = string_is_affirmative (prop->value());
2308 /* do it twice to force the change */
2310 tact->set_active (!yn);
2311 tact->set_active (yn);
2314 if ((prop = node.property (X_("editor-list-page")))) {
2315 _the_notebook.set_current_page (atoi (prop->value ()));
2318 if ((prop = node.property (X_("show-marker-lines")))) {
2319 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2321 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2322 bool yn = string_is_affirmative (prop->value ());
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2328 XMLNodeList children = node.children ();
2329 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2330 selection->set_state (**i, Stateful::current_state_version);
2331 _regions->set_state (**i);
2334 if ((prop = node.property ("maximised"))) {
2335 bool yn = string_is_affirmative (prop->value());
2336 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2338 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2339 bool fs = tact && tact->get_active();
2341 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2345 if ((prop = node.property ("nudge-clock-value"))) {
2347 sscanf (prop->value().c_str(), "%" PRId64, &f);
2348 nudge_clock->set (f);
2350 nudge_clock->set_mode (AudioClock::Timecode);
2351 nudge_clock->set (_session->frame_rate() * 5, true);
2358 Editor::get_state ()
2360 XMLNode* node = new XMLNode ("Editor");
2363 id().print (buf, sizeof (buf));
2364 node->add_property ("id", buf);
2366 if (is_realized()) {
2367 Glib::RefPtr<Gdk::Window> win = get_window();
2369 int x, y, width, height;
2370 win->get_root_origin(x, y);
2371 win->get_size(width, height);
2373 XMLNode* geometry = new XMLNode ("geometry");
2375 snprintf(buf, sizeof(buf), "%d", width);
2376 geometry->add_property("x-size", string(buf));
2377 snprintf(buf, sizeof(buf), "%d", height);
2378 geometry->add_property("y-size", string(buf));
2379 snprintf(buf, sizeof(buf), "%d", x);
2380 geometry->add_property("x-pos", string(buf));
2381 snprintf(buf, sizeof(buf), "%d", y);
2382 geometry->add_property("y-pos", string(buf));
2383 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2384 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2385 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2386 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2387 geometry->add_property("edit-vertical-pane-pos", string(buf));
2389 node->add_child_nocopy (*geometry);
2392 maybe_add_mixer_strip_width (*node);
2394 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2396 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2397 node->add_property ("zoom", buf);
2398 node->add_property ("snap-to", enum_2_string (_snap_type));
2399 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2400 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2401 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2402 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2403 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2404 node->add_property ("edit-point", enum_2_string (_edit_point));
2405 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2406 node->add_property ("visible-track-count", buf);
2408 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2409 node->add_property ("playhead", buf);
2410 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2411 node->add_property ("left-frame", buf);
2412 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2413 node->add_property ("y-origin", buf);
2415 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2416 node->add_property ("maximised", _maximised ? "yes" : "no");
2417 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2418 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2419 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2420 node->add_property ("mouse-mode", enum2str(mouse_mode));
2421 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2422 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2424 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2426 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2427 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2430 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2432 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2433 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2436 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2437 node->add_property (X_("editor-list-page"), buf);
2439 if (button_bindings) {
2440 XMLNode* bb = new XMLNode (X_("Buttons"));
2441 button_bindings->save (*bb);
2442 node->add_child_nocopy (*bb);
2445 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2447 node->add_child_nocopy (selection->get_state ());
2448 node->add_child_nocopy (_regions->get_state ());
2450 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2451 node->add_property ("nudge-clock-value", buf);
2456 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2457 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2459 * @return pair: TimeAxisView that y is over, layer index.
2461 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2462 * in stacked or expanded region display mode, otherwise 0.
2464 std::pair<TimeAxisView *, double>
2465 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2467 if (!trackview_relative_offset) {
2468 y -= _trackview_group->canvas_origin().y;
2472 return std::make_pair ( (TimeAxisView *) 0, 0);
2475 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2477 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2484 return std::make_pair ( (TimeAxisView *) 0, 0);
2487 /** Snap a position to the grid, if appropriate, taking into account current
2488 * grid settings and also the state of any snap modifier keys that may be pressed.
2489 * @param start Position to snap.
2490 * @param event Event to get current key modifier information from, or 0.
2493 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2495 if (!_session || !event) {
2499 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2500 if (_snap_mode == SnapOff) {
2501 snap_to_internal (start, direction, for_mark);
2504 if (_snap_mode != SnapOff) {
2505 snap_to_internal (start, direction, for_mark);
2511 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2513 if (!_session || _snap_mode == SnapOff) {
2517 snap_to_internal (start, direction, for_mark);
2521 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2523 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2524 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2526 switch (_snap_type) {
2527 case SnapToTimecodeFrame:
2528 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2529 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2531 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2535 case SnapToTimecodeSeconds:
2536 if (_session->config.get_timecode_offset_negative()) {
2537 start += _session->config.get_timecode_offset ();
2539 start -= _session->config.get_timecode_offset ();
2541 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2542 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2544 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2547 if (_session->config.get_timecode_offset_negative()) {
2548 start -= _session->config.get_timecode_offset ();
2550 start += _session->config.get_timecode_offset ();
2554 case SnapToTimecodeMinutes:
2555 if (_session->config.get_timecode_offset_negative()) {
2556 start += _session->config.get_timecode_offset ();
2558 start -= _session->config.get_timecode_offset ();
2560 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2561 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2563 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2565 if (_session->config.get_timecode_offset_negative()) {
2566 start -= _session->config.get_timecode_offset ();
2568 start += _session->config.get_timecode_offset ();
2572 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2578 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2580 const framepos_t one_second = _session->frame_rate();
2581 const framepos_t one_minute = _session->frame_rate() * 60;
2582 framepos_t presnap = start;
2586 switch (_snap_type) {
2587 case SnapToTimecodeFrame:
2588 case SnapToTimecodeSeconds:
2589 case SnapToTimecodeMinutes:
2590 return timecode_snap_to_internal (start, direction, for_mark);
2593 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2594 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2596 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2601 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2602 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2604 start = (framepos_t) floor ((double) start / one_second) * one_second;
2609 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2610 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2612 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2617 start = _session->tempo_map().round_to_bar (start, direction);
2621 start = _session->tempo_map().round_to_beat (start, direction);
2624 case SnapToBeatDiv128:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2627 case SnapToBeatDiv64:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2630 case SnapToBeatDiv32:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2633 case SnapToBeatDiv28:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2636 case SnapToBeatDiv24:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2639 case SnapToBeatDiv20:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2642 case SnapToBeatDiv16:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2645 case SnapToBeatDiv14:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2648 case SnapToBeatDiv12:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2651 case SnapToBeatDiv10:
2652 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2654 case SnapToBeatDiv8:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2657 case SnapToBeatDiv7:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2660 case SnapToBeatDiv6:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2663 case SnapToBeatDiv5:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2666 case SnapToBeatDiv4:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2669 case SnapToBeatDiv3:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2672 case SnapToBeatDiv2:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2681 _session->locations()->marks_either_side (start, before, after);
2683 if (before == max_framepos && after == max_framepos) {
2684 /* No marks to snap to, so just don't snap */
2686 } else if (before == max_framepos) {
2688 } else if (after == max_framepos) {
2690 } else if (before != max_framepos && after != max_framepos) {
2691 /* have before and after */
2692 if ((start - before) < (after - start)) {
2701 case SnapToRegionStart:
2702 case SnapToRegionEnd:
2703 case SnapToRegionSync:
2704 case SnapToRegionBoundary:
2705 if (!region_boundary_cache.empty()) {
2707 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2708 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2710 if (direction > 0) {
2711 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2713 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2716 if (next != region_boundary_cache.begin ()) {
2721 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2722 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2724 if (start > (p + n) / 2) {
2733 switch (_snap_mode) {
2739 if (presnap > start) {
2740 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2744 } else if (presnap < start) {
2745 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2751 /* handled at entry */
2759 Editor::setup_toolbar ()
2761 HBox* mode_box = manage(new HBox);
2762 mode_box->set_border_width (2);
2763 mode_box->set_spacing(2);
2765 HBox* mouse_mode_box = manage (new HBox);
2766 HBox* mouse_mode_hbox = manage (new HBox);
2767 VBox* mouse_mode_vbox = manage (new VBox);
2768 Alignment* mouse_mode_align = manage (new Alignment);
2770 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2771 //mouse_mode_size_group->add_widget (smart_mode_button);
2772 mouse_mode_size_group->add_widget (mouse_move_button);
2773 mouse_mode_size_group->add_widget (mouse_cut_button);
2774 mouse_mode_size_group->add_widget (mouse_select_button);
2775 mouse_mode_size_group->add_widget (mouse_zoom_button);
2776 mouse_mode_size_group->add_widget (mouse_gain_button);
2777 mouse_mode_size_group->add_widget (mouse_timefx_button);
2778 mouse_mode_size_group->add_widget (mouse_audition_button);
2779 mouse_mode_size_group->add_widget (mouse_draw_button);
2780 mouse_mode_size_group->add_widget (internal_edit_button);
2782 if (!ARDOUR::Profile->get_small_screen()) {
2783 /* make them just a bit bigger */
2784 mouse_move_button.set_size_request (24, 30);
2786 /* make them just a bit taller */
2787 mouse_move_button.set_size_request (-1, 30);
2789 mouse_mode_hbox->set_spacing (2);
2791 if (!ARDOUR::Profile->get_trx()) {
2792 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2795 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2796 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2797 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2798 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2800 if (!ARDOUR::Profile->get_trx()) {
2801 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2802 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2803 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2804 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2805 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2808 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2810 mouse_mode_align->add (*mouse_mode_vbox);
2811 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2813 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2815 edit_mode_selector.set_name ("mouse mode button");
2816 set_size_request_to_display_given_text (edit_mode_selector, _("Ripple"), 30, 2);
2817 edit_mode_selector.add_elements (ArdourButton::Inset);
2819 if (!ARDOUR::Profile->get_trx()) {
2820 mode_box->pack_start (edit_mode_selector, false, false);
2822 mode_box->pack_start (*mouse_mode_box, false, false);
2824 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2825 _mouse_mode_tearoff->set_name ("MouseModeBase");
2826 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2828 if (Profile->get_sae() || Profile->get_mixbus() ) {
2829 _mouse_mode_tearoff->set_can_be_torn_off (false);
2832 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2833 &_mouse_mode_tearoff->tearoff_window()));
2834 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2835 &_mouse_mode_tearoff->tearoff_window(), 1));
2836 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2837 &_mouse_mode_tearoff->tearoff_window()));
2838 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2839 &_mouse_mode_tearoff->tearoff_window(), 1));
2843 _zoom_box.set_spacing (2);
2844 _zoom_box.set_border_width (2);
2848 zoom_in_button.set_name ("zoom button");
2849 // zoom_in_button.add_elements ( ArdourButton::Inset );
2850 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2851 zoom_in_button.set_image(::get_icon ("zoom_in"));
2852 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2853 zoom_in_button.set_related_action (act);
2855 zoom_out_button.set_name ("zoom button");
2856 // zoom_out_button.add_elements ( ArdourButton::Inset );
2857 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2858 zoom_out_button.set_image(::get_icon ("zoom_out"));
2859 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2860 zoom_out_button.set_related_action (act);
2862 zoom_out_full_button.set_name ("zoom button");
2863 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2864 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2865 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2866 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2867 zoom_out_full_button.set_related_action (act);
2869 zoom_focus_selector.set_name ("zoom button");
2870 set_size_request_to_display_given_text (zoom_focus_selector, _("Edit Point"), 30, 2);
2871 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2873 if (ARDOUR::Profile->get_mixbus()) {
2874 _zoom_box.pack_start (zoom_out_button, false, false);
2875 _zoom_box.pack_start (zoom_in_button, false, false);
2876 _zoom_box.pack_start (zoom_out_full_button, false, false);
2877 } else if (ARDOUR::Profile->get_trx()) {
2878 mode_box->pack_start (zoom_out_button, false, false);
2879 mode_box->pack_start (zoom_in_button, false, false);
2881 _zoom_box.pack_start (zoom_out_button, false, false);
2882 _zoom_box.pack_start (zoom_in_button, false, false);
2883 _zoom_box.pack_start (zoom_out_full_button, false, false);
2884 _zoom_box.pack_start (zoom_focus_selector, false, false);
2887 /* Track zoom buttons */
2888 visible_tracks_selector.set_name ("zoom button");
2889 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2890 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2892 tav_expand_button.set_name ("zoom button");
2893 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2894 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2895 tav_expand_button.set_size_request (-1, 20);
2896 tav_expand_button.set_image(::get_icon ("tav_exp"));
2897 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2898 tav_expand_button.set_related_action (act);
2900 tav_shrink_button.set_name ("zoom button");
2901 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2902 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2903 tav_shrink_button.set_size_request (-1, 20);
2904 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2905 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2906 tav_shrink_button.set_related_action (act);
2908 if (!ARDOUR::Profile->get_trx()) {
2909 _zoom_box.pack_start (visible_tracks_selector);
2911 _zoom_box.pack_start (tav_shrink_button);
2912 _zoom_box.pack_start (tav_expand_button);
2914 if (!ARDOUR::Profile->get_trx()) {
2915 _zoom_tearoff = manage (new TearOff (_zoom_box));
2917 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918 &_zoom_tearoff->tearoff_window()));
2919 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920 &_zoom_tearoff->tearoff_window(), 0));
2921 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2922 &_zoom_tearoff->tearoff_window()));
2923 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2924 &_zoom_tearoff->tearoff_window(), 0));
2927 if (Profile->get_sae() || Profile->get_mixbus() ) {
2928 _zoom_tearoff->set_can_be_torn_off (false);
2931 snap_box.set_spacing (2);
2932 snap_box.set_border_width (2);
2934 snap_type_selector.set_name ("mouse mode button");
2935 snap_type_selector.add_elements (ArdourButton::Inset);
2936 set_size_request_to_display_given_text (snap_type_selector, _("Region starts"), 34, 2);
2938 snap_mode_selector.set_name ("mouse mode button");
2939 snap_mode_selector.add_elements (ArdourButton::Inset);
2940 set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic"), 34, 2);
2942 edit_point_selector.set_name ("mouse mode button");
2943 edit_point_selector.add_elements (ArdourButton::Inset);
2944 set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 34, 2);
2946 snap_box.pack_start (snap_mode_selector, false, false);
2947 snap_box.pack_start (snap_type_selector, false, false);
2948 snap_box.pack_start (edit_point_selector, false, false);
2952 HBox *nudge_box = manage (new HBox);
2953 nudge_box->set_spacing (2);
2954 nudge_box->set_border_width (2);
2956 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2957 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2959 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2960 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 nudge_box->pack_start (nudge_backward_button, false, false);
2963 nudge_box->pack_start (nudge_forward_button, false, false);
2964 nudge_box->pack_start (*nudge_clock, false, false);
2967 /* Pack everything in... */
2969 HBox* hbox = manage (new HBox);
2970 hbox->set_spacing(2);
2972 _tools_tearoff = manage (new TearOff (*hbox));
2973 _tools_tearoff->set_name ("MouseModeBase");
2974 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2976 if (Profile->get_sae() || Profile->get_mixbus()) {
2977 _tools_tearoff->set_can_be_torn_off (false);
2980 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981 &_tools_tearoff->tearoff_window()));
2982 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983 &_tools_tearoff->tearoff_window(), 0));
2984 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_tools_tearoff->tearoff_window()));
2986 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_tools_tearoff->tearoff_window(), 0));
2989 toolbar_hbox.set_spacing (2);
2990 toolbar_hbox.set_border_width (1);
2992 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2993 if (!ARDOUR::Profile->get_trx()) {
2994 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2995 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2998 if (!ARDOUR::Profile->get_trx()) {
2999 hbox->pack_start (snap_box, false, false);
3000 if (!Profile->get_small_screen()) {
3001 hbox->pack_start (*nudge_box, false, false);
3003 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3006 hbox->pack_start (panic_box, false, false);
3010 toolbar_base.set_name ("ToolBarBase");
3011 toolbar_base.add (toolbar_hbox);
3013 _toolbar_viewport.add (toolbar_base);
3014 /* stick to the required height but allow width to vary if there's not enough room */
3015 _toolbar_viewport.set_size_request (1, -1);
3017 toolbar_frame.set_shadow_type (SHADOW_OUT);
3018 toolbar_frame.set_name ("BaseFrame");
3019 toolbar_frame.add (_toolbar_viewport);
3023 Editor::build_edit_point_menu ()
3025 using namespace Menu_Helpers;
3027 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3028 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3029 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3033 Editor::build_edit_mode_menu ()
3035 using namespace Menu_Helpers;
3037 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3038 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3039 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3040 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3044 Editor::build_snap_mode_menu ()
3046 using namespace Menu_Helpers;
3048 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3049 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3050 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3054 Editor::build_snap_type_menu ()
3056 using namespace Menu_Helpers;
3058 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3059 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3060 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3061 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3062 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3091 Editor::setup_tooltips ()
3093 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3094 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3095 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3096 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3097 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3098 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3099 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3100 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3101 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3102 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3103 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3104 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3105 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3106 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3107 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3108 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3109 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3110 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3111 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3112 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3113 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3114 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3115 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3116 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3117 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3121 Editor::convert_drop_to_paths (
3122 vector<string>& paths,
3123 const RefPtr<Gdk::DragContext>& /*context*/,
3126 const SelectionData& data,
3130 if (_session == 0) {
3134 vector<string> uris = data.get_uris();
3138 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3139 are actually URI lists. So do it by hand.
3142 if (data.get_target() != "text/plain") {
3146 /* Parse the "uri-list" format that Nautilus provides,
3147 where each pathname is delimited by \r\n.
3149 THERE MAY BE NO NULL TERMINATING CHAR!!!
3152 string txt = data.get_text();
3156 p = (char *) malloc (txt.length() + 1);
3157 txt.copy (p, txt.length(), 0);
3158 p[txt.length()] = '\0';
3164 while (g_ascii_isspace (*p))
3168 while (*q && (*q != '\n') && (*q != '\r')) {
3175 while (q > p && g_ascii_isspace (*q))
3180 uris.push_back (string (p, q - p + 1));
3184 p = strchr (p, '\n');
3196 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3197 if ((*i).substr (0,7) == "file://") {
3198 paths.push_back (Glib::filename_from_uri (*i));
3206 Editor::new_tempo_section ()
3211 Editor::map_transport_state ()
3213 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3215 if (_session && _session->transport_stopped()) {
3216 have_pending_keyboard_selection = false;
3219 update_loop_range_view ();
3225 Editor::begin_reversible_command (string name)
3228 _session->begin_reversible_command (name);
3233 Editor::begin_reversible_command (GQuark q)
3236 _session->begin_reversible_command (q);
3241 Editor::commit_reversible_command ()
3244 _session->commit_reversible_command ();
3249 Editor::history_changed ()
3253 if (undo_action && _session) {
3254 if (_session->undo_depth() == 0) {
3255 label = S_("Command|Undo");
3257 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3259 undo_action->property_label() = label;
3262 if (redo_action && _session) {
3263 if (_session->redo_depth() == 0) {
3266 label = string_compose(_("Redo (%1)"), _session->next_redo());
3268 redo_action->property_label() = label;
3273 Editor::duplicate_range (bool with_dialog)
3277 RegionSelection rs = get_regions_from_selection_and_entered ();
3279 if ( selection->time.length() == 0 && rs.empty()) {
3285 ArdourDialog win (_("Duplicate"));
3286 Label label (_("Number of duplications:"));
3287 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3288 SpinButton spinner (adjustment, 0.0, 1);
3291 win.get_vbox()->set_spacing (12);
3292 win.get_vbox()->pack_start (hbox);
3293 hbox.set_border_width (6);
3294 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3296 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3297 place, visually. so do this by hand.
3300 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3301 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3302 spinner.grab_focus();
3308 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3309 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3310 win.set_default_response (RESPONSE_ACCEPT);
3312 spinner.grab_focus ();
3314 switch (win.run ()) {
3315 case RESPONSE_ACCEPT:
3321 times = adjustment.get_value();
3324 if ((current_mouse_mode() == Editing::MouseRange)) {
3325 if (selection->time.length()) {
3326 duplicate_selection (times);
3328 } else if (get_smart_mode()) {
3329 if (selection->time.length()) {
3330 duplicate_selection (times);
3332 duplicate_some_regions (rs, times);
3334 duplicate_some_regions (rs, times);
3339 Editor::set_edit_mode (EditMode m)
3341 Config->set_edit_mode (m);
3345 Editor::cycle_edit_mode ()
3347 switch (Config->get_edit_mode()) {
3349 if (Profile->get_sae()) {
3350 Config->set_edit_mode (Lock);
3352 Config->set_edit_mode (Ripple);
3357 Config->set_edit_mode (Lock);
3360 Config->set_edit_mode (Slide);
3366 Editor::edit_mode_selection_done ( EditMode m )
3368 Config->set_edit_mode ( m );
3372 Editor::snap_type_selection_done (SnapType snaptype)
3374 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3376 ract->set_active ();
3381 Editor::snap_mode_selection_done (SnapMode mode)
3383 RefPtr<RadioAction> ract = snap_mode_action (mode);
3386 ract->set_active (true);
3391 Editor::cycle_edit_point (bool with_marker)
3393 switch (_edit_point) {
3395 set_edit_point_preference (EditAtPlayhead);
3397 case EditAtPlayhead:
3399 set_edit_point_preference (EditAtSelectedMarker);
3401 set_edit_point_preference (EditAtMouse);
3404 case EditAtSelectedMarker:
3405 set_edit_point_preference (EditAtMouse);
3411 Editor::edit_point_selection_done (EditPoint ep)
3413 set_edit_point_preference ( ep );
3417 Editor::build_zoom_focus_menu ()
3419 using namespace Menu_Helpers;
3421 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3422 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3423 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3424 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3425 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3426 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3430 Editor::zoom_focus_selection_done ( ZoomFocus f )
3432 RefPtr<RadioAction> ract = zoom_focus_action (f);
3434 ract->set_active ();
3439 Editor::build_track_count_menu ()
3441 using namespace Menu_Helpers;
3443 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3444 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3445 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3446 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3447 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3448 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3449 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3450 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3451 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3452 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3453 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3454 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3458 Editor::set_visible_track_count (int32_t n)
3460 _visible_track_count = n;
3462 /* if the canvas hasn't really been allocated any size yet, just
3463 record the desired number of visible tracks and return. when canvas
3464 allocation happens, we will get called again and then we can do the
3468 if (_visible_canvas_height <= 1) {
3475 if (_visible_track_count > 0) {
3476 h = _visible_canvas_height / _visible_track_count;
3477 std::ostringstream s;
3478 s << _visible_track_count;
3480 } else if (_visible_track_count == 0) {
3481 h = _visible_canvas_height / track_views.size();
3484 /* negative value means that the visible track count has
3485 been overridden by explicit track height changes.
3487 visible_tracks_selector.set_text (X_("*"));
3491 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3492 (*i)->set_height (h);
3495 if (str != visible_tracks_selector.get_text()) {
3496 visible_tracks_selector.set_text (str);
3501 Editor::override_visible_track_count ()
3503 _visible_track_count = -_visible_track_count;
3507 Editor::edit_controls_button_release (GdkEventButton* ev)
3509 if (Keyboard::is_context_menu_event (ev)) {
3510 ARDOUR_UI::instance()->add_route (this);
3511 } else if (ev->button == 1) {
3512 selection->clear_tracks ();
3519 Editor::mouse_select_button_release (GdkEventButton* ev)
3521 /* this handles just right-clicks */
3523 if (ev->button != 3) {
3531 Editor::set_zoom_focus (ZoomFocus f)
3533 string str = zoom_focus_strings[(int)f];
3535 if (str != zoom_focus_selector.get_text()) {
3536 zoom_focus_selector.set_text (str);
3539 if (zoom_focus != f) {
3546 Editor::cycle_zoom_focus ()
3548 switch (zoom_focus) {
3550 set_zoom_focus (ZoomFocusRight);
3552 case ZoomFocusRight:
3553 set_zoom_focus (ZoomFocusCenter);
3555 case ZoomFocusCenter:
3556 set_zoom_focus (ZoomFocusPlayhead);
3558 case ZoomFocusPlayhead:
3559 set_zoom_focus (ZoomFocusMouse);
3561 case ZoomFocusMouse:
3562 set_zoom_focus (ZoomFocusEdit);
3565 set_zoom_focus (ZoomFocusLeft);
3571 Editor::ensure_float (Window& win)
3573 win.set_transient_for (*this);
3577 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3579 /* recover or initialize pane positions. do this here rather than earlier because
3580 we don't want the positions to change the child allocations, which they seem to do.
3586 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3595 XMLNode* geometry = find_named_node (*node, "geometry");
3597 if (which == static_cast<Paned*> (&edit_pane)) {
3599 if (done & Horizontal) {
3603 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3604 _notebook_shrunk = string_is_affirmative (prop->value ());
3607 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3608 /* initial allocation is 90% to canvas, 10% to notebook */
3609 pos = (int) floor (alloc.get_width() * 0.90f);
3610 snprintf (buf, sizeof(buf), "%d", pos);
3612 pos = atoi (prop->value());
3615 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3616 edit_pane.set_position (pos);
3619 done = (Pane) (done | Horizontal);
3621 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3623 if (done & Vertical) {
3627 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3628 /* initial allocation is 90% to canvas, 10% to summary */
3629 pos = (int) floor (alloc.get_height() * 0.90f);
3630 snprintf (buf, sizeof(buf), "%d", pos);
3633 pos = atoi (prop->value());
3636 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3637 editor_summary_pane.set_position (pos);
3640 done = (Pane) (done | Vertical);
3645 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3647 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3648 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3649 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3650 top_hbox.remove (toolbar_frame);
3655 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3657 if (toolbar_frame.get_parent() == 0) {
3658 top_hbox.pack_end (toolbar_frame);
3663 Editor::set_show_measures (bool yn)
3665 if (_show_measures != yn) {
3668 if ((_show_measures = yn) == true) {
3670 tempo_lines->show();
3673 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3674 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3676 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3677 draw_measures (begin, end);
3685 Editor::toggle_follow_playhead ()
3687 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3689 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3690 set_follow_playhead (tact->get_active());
3694 /** @param yn true to follow playhead, otherwise false.
3695 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3698 Editor::set_follow_playhead (bool yn, bool catch_up)
3700 if (_follow_playhead != yn) {
3701 if ((_follow_playhead = yn) == true && catch_up) {
3703 reset_x_origin_to_follow_playhead ();
3710 Editor::toggle_stationary_playhead ()
3712 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3714 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3715 set_stationary_playhead (tact->get_active());
3720 Editor::set_stationary_playhead (bool yn)
3722 if (_stationary_playhead != yn) {
3723 if ((_stationary_playhead = yn) == true) {
3725 // FIXME need a 3.0 equivalent of this 2.X call
3726 // update_current_screen ();
3733 Editor::playlist_selector () const
3735 return *_playlist_selector;
3739 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3743 switch (_snap_type) {
3748 case SnapToBeatDiv128:
3751 case SnapToBeatDiv64:
3754 case SnapToBeatDiv32:
3757 case SnapToBeatDiv28:
3760 case SnapToBeatDiv24:
3763 case SnapToBeatDiv20:
3766 case SnapToBeatDiv16:
3769 case SnapToBeatDiv14:
3772 case SnapToBeatDiv12:
3775 case SnapToBeatDiv10:
3778 case SnapToBeatDiv8:
3781 case SnapToBeatDiv7:
3784 case SnapToBeatDiv6:
3787 case SnapToBeatDiv5:
3790 case SnapToBeatDiv4:
3793 case SnapToBeatDiv3:
3796 case SnapToBeatDiv2:
3802 return _session->tempo_map().meter_at (position).divisions_per_bar();
3807 case SnapToTimecodeFrame:
3808 case SnapToTimecodeSeconds:
3809 case SnapToTimecodeMinutes:
3812 case SnapToRegionStart:
3813 case SnapToRegionEnd:
3814 case SnapToRegionSync:
3815 case SnapToRegionBoundary:
3825 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3829 ret = nudge_clock->current_duration (pos);
3830 next = ret + 1; /* XXXX fix me */
3836 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3838 ArdourDialog dialog (_("Playlist Deletion"));
3839 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3840 "If it is kept, its audio files will not be cleaned.\n"
3841 "If it is deleted, audio files used by it alone will be cleaned."),
3844 dialog.set_position (WIN_POS_CENTER);
3845 dialog.get_vbox()->pack_start (label);
3849 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3850 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3851 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3853 switch (dialog.run ()) {
3854 case RESPONSE_ACCEPT:
3855 /* delete the playlist */
3859 case RESPONSE_REJECT:
3860 /* keep the playlist */
3872 Editor::audio_region_selection_covers (framepos_t where)
3874 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3875 if ((*a)->region()->covers (where)) {
3884 Editor::prepare_for_cleanup ()
3886 cut_buffer->clear_regions ();
3887 cut_buffer->clear_playlists ();
3889 selection->clear_regions ();
3890 selection->clear_playlists ();
3892 _regions->suspend_redisplay ();
3896 Editor::finish_cleanup ()
3898 _regions->resume_redisplay ();
3902 Editor::transport_loop_location()
3905 return _session->locations()->auto_loop_location();
3912 Editor::transport_punch_location()
3915 return _session->locations()->auto_punch_location();
3922 Editor::control_layout_scroll (GdkEventScroll* ev)
3924 /* Just forward to the normal canvas scroll method. The coordinate
3925 systems are different but since the canvas is always larger than the
3926 track headers, and aligned with the trackview area, this will work.
3928 In the not too distant future this layout is going away anyway and
3929 headers will be on the canvas.
3931 return canvas_scroll_event (ev, false);
3935 Editor::session_state_saved (string)
3938 _snapshots->redisplay ();
3942 Editor::update_tearoff_visibility()
3944 bool visible = Config->get_keep_tearoffs();
3945 _mouse_mode_tearoff->set_visible (visible);
3946 _tools_tearoff->set_visible (visible);
3947 if (_zoom_tearoff) {
3948 _zoom_tearoff->set_visible (visible);
3953 Editor::maximise_editing_space ()
3965 Editor::restore_editing_space ()
3977 * Make new playlists for a given track and also any others that belong
3978 * to the same active route group with the `select' property.
3983 Editor::new_playlists (TimeAxisView* v)
3985 begin_reversible_command (_("new playlists"));
3986 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3987 _session->playlists->get (playlists);
3988 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3989 commit_reversible_command ();
3993 * Use a copy of the current playlist for a given track and also any others that belong
3994 * to the same active route group with the `select' property.
3999 Editor::copy_playlists (TimeAxisView* v)
4001 begin_reversible_command (_("copy playlists"));
4002 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4003 _session->playlists->get (playlists);
4004 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4005 commit_reversible_command ();
4008 /** Clear the current playlist for a given track and also any others that belong
4009 * to the same active route group with the `select' property.
4014 Editor::clear_playlists (TimeAxisView* v)
4016 begin_reversible_command (_("clear playlists"));
4017 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4018 _session->playlists->get (playlists);
4019 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4020 commit_reversible_command ();
4024 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4026 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4030 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4032 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4036 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4038 atv.clear_playlist ();
4042 Editor::on_key_press_event (GdkEventKey* ev)
4044 return key_press_focus_accelerator_handler (*this, ev);
4048 Editor::on_key_release_event (GdkEventKey* ev)
4050 return Gtk::Window::on_key_release_event (ev);
4051 // return key_press_focus_accelerator_handler (*this, ev);
4054 /** Queue up a change to the viewport x origin.
4055 * @param frame New x origin.
4058 Editor::reset_x_origin (framepos_t frame)
4060 pending_visual_change.add (VisualChange::TimeOrigin);
4061 pending_visual_change.time_origin = frame;
4062 ensure_visual_change_idle_handler ();
4066 Editor::reset_y_origin (double y)
4068 pending_visual_change.add (VisualChange::YOrigin);
4069 pending_visual_change.y_origin = y;
4070 ensure_visual_change_idle_handler ();
4074 Editor::reset_zoom (framecnt_t spp)
4076 if (spp == samples_per_pixel) {
4080 pending_visual_change.add (VisualChange::ZoomLevel);
4081 pending_visual_change.samples_per_pixel = spp;
4082 ensure_visual_change_idle_handler ();
4086 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4088 reset_x_origin (frame);
4091 if (!no_save_visual) {
4092 undo_visual_stack.push_back (current_visual_state(false));
4096 Editor::VisualState::VisualState (bool with_tracks)
4097 : gui_state (with_tracks ? new GUIObjectState : 0)
4101 Editor::VisualState::~VisualState ()
4106 Editor::VisualState*
4107 Editor::current_visual_state (bool with_tracks)
4109 VisualState* vs = new VisualState (with_tracks);
4110 vs->y_position = vertical_adjustment.get_value();
4111 vs->samples_per_pixel = samples_per_pixel;
4112 vs->leftmost_frame = leftmost_frame;
4113 vs->zoom_focus = zoom_focus;
4116 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4123 Editor::undo_visual_state ()
4125 if (undo_visual_stack.empty()) {
4129 VisualState* vs = undo_visual_stack.back();
4130 undo_visual_stack.pop_back();
4133 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4135 use_visual_state (*vs);
4139 Editor::redo_visual_state ()
4141 if (redo_visual_stack.empty()) {
4145 VisualState* vs = redo_visual_stack.back();
4146 redo_visual_stack.pop_back();
4148 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4150 use_visual_state (*vs);
4154 Editor::swap_visual_state ()
4156 if (undo_visual_stack.empty()) {
4157 redo_visual_state ();
4159 undo_visual_state ();
4164 Editor::use_visual_state (VisualState& vs)
4166 PBD::Unwinder<bool> nsv (no_save_visual, true);
4167 DisplaySuspender ds;
4169 vertical_adjustment.set_value (vs.y_position);
4171 set_zoom_focus (vs.zoom_focus);
4172 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4175 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4177 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4178 (*i)->reset_visual_state ();
4182 _routes->update_visibility ();
4185 /** This is the core function that controls the zoom level of the canvas. It is called
4186 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4187 * @param spp new number of samples per pixel
4190 Editor::set_samples_per_pixel (framecnt_t spp)
4196 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4197 const framecnt_t lots_of_pixels = 4000;
4199 /* if the zoom level is greater than what you'd get trying to display 3
4200 * days of audio on a really big screen, then it's too big.
4203 if (spp * lots_of_pixels > three_days) {
4207 samples_per_pixel = spp;
4210 tempo_lines->tempo_map_changed();
4213 bool const showing_time_selection = selection->time.length() > 0;
4215 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4216 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4217 (*i)->reshow_selection (selection->time);
4221 ZoomChanged (); /* EMIT_SIGNAL */
4223 ArdourCanvas::GtkCanvasViewport* c;
4225 c = get_track_canvas();
4227 c->canvas()->zoomed ();
4230 if (playhead_cursor) {
4231 playhead_cursor->set_position (playhead_cursor->current_frame ());
4234 refresh_location_display();
4235 _summary->set_overlays_dirty ();
4237 update_marker_labels ();
4243 Editor::queue_visual_videotimeline_update ()
4246 * pending_visual_change.add (VisualChange::VideoTimeline);
4247 * or maybe even more specific: which videotimeline-image
4248 * currently it calls update_video_timeline() to update
4249 * _all outdated_ images on the video-timeline.
4250 * see 'exposeimg()' in video_image_frame.cc
4252 ensure_visual_change_idle_handler ();
4256 Editor::ensure_visual_change_idle_handler ()
4258 if (pending_visual_change.idle_handler_id < 0) {
4259 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4260 pending_visual_change.being_handled = false;
4265 Editor::_idle_visual_changer (void* arg)
4267 return static_cast<Editor*>(arg)->idle_visual_changer ();
4271 Editor::idle_visual_changer ()
4273 /* set_horizontal_position() below (and maybe other calls) call
4274 gtk_main_iteration(), so it's possible that a signal will be handled
4275 half-way through this method. If this signal wants an
4276 idle_visual_changer we must schedule another one after this one, so
4277 mark the idle_handler_id as -1 here to allow that. Also make a note
4278 that we are doing the visual change, so that changes in response to
4279 super-rapid-screen-update can be dropped if we are still processing
4283 pending_visual_change.idle_handler_id = -1;
4284 pending_visual_change.being_handled = true;
4286 VisualChange vc = pending_visual_change;
4288 pending_visual_change.pending = (VisualChange::Type) 0;
4290 visual_changer (vc);
4292 pending_visual_change.being_handled = false;
4294 return 0; /* this is always a one-shot call */
4298 Editor::visual_changer (const VisualChange& vc)
4300 double const last_time_origin = horizontal_position ();
4302 if (vc.pending & VisualChange::ZoomLevel) {
4303 set_samples_per_pixel (vc.samples_per_pixel);
4305 compute_fixed_ruler_scale ();
4307 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4308 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4310 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4311 current_bbt_points_begin, current_bbt_points_end);
4312 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4313 current_bbt_points_begin, current_bbt_points_end);
4314 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4316 update_video_timeline();
4319 if (vc.pending & VisualChange::TimeOrigin) {
4320 set_horizontal_position (vc.time_origin / samples_per_pixel);
4323 if (vc.pending & VisualChange::YOrigin) {
4324 vertical_adjustment.set_value (vc.y_origin);
4327 if (last_time_origin == horizontal_position ()) {
4328 /* changed signal not emitted */
4329 update_fixed_rulers ();
4330 redisplay_tempo (true);
4333 if (!(vc.pending & VisualChange::ZoomLevel)) {
4334 update_video_timeline();
4337 _summary->set_overlays_dirty ();
4340 struct EditorOrderTimeAxisSorter {
4341 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4342 return a->order () < b->order ();
4347 Editor::sort_track_selection (TrackViewList& sel)
4349 EditorOrderTimeAxisSorter cmp;
4354 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4357 framepos_t where = 0;
4358 EditPoint ep = _edit_point;
4360 if (from_context_menu && (ep == EditAtMouse)) {
4361 return canvas_event_sample (&context_click_event, 0, 0);
4364 if (entered_marker) {
4365 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4366 return entered_marker->position();
4369 if (ignore_playhead && ep == EditAtPlayhead) {
4370 ep = EditAtSelectedMarker;
4374 case EditAtPlayhead:
4375 where = _session->audible_frame();
4376 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4379 case EditAtSelectedMarker:
4380 if (!selection->markers.empty()) {
4382 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4385 where = loc->start();
4389 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4397 if (!mouse_frame (where, ignored)) {
4398 /* XXX not right but what can we do ? */
4402 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4410 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4412 if (!_session) return;
4414 begin_reversible_command (cmd);
4418 if ((tll = transport_loop_location()) == 0) {
4419 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4420 XMLNode &before = _session->locations()->get_state();
4421 _session->locations()->add (loc, true);
4422 _session->set_auto_loop_location (loc);
4423 XMLNode &after = _session->locations()->get_state();
4424 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4426 XMLNode &before = tll->get_state();
4427 tll->set_hidden (false, this);
4428 tll->set (start, end);
4429 XMLNode &after = tll->get_state();
4430 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4433 commit_reversible_command ();
4437 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4439 if (!_session) return;
4441 begin_reversible_command (cmd);
4445 if ((tpl = transport_punch_location()) == 0) {
4446 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4447 XMLNode &before = _session->locations()->get_state();
4448 _session->locations()->add (loc, true);
4449 _session->set_auto_punch_location (loc);
4450 XMLNode &after = _session->locations()->get_state();
4451 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4454 XMLNode &before = tpl->get_state();
4455 tpl->set_hidden (false, this);
4456 tpl->set (start, end);
4457 XMLNode &after = tpl->get_state();
4458 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4461 commit_reversible_command ();
4464 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4465 * @param rs List to which found regions are added.
4466 * @param where Time to look at.
4467 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4470 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4472 const TrackViewList* tracks;
4475 tracks = &track_views;
4480 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4485 boost::shared_ptr<Track> tr;
4486 boost::shared_ptr<Playlist> pl;
4488 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4490 boost::shared_ptr<RegionList> regions = pl->regions_at (
4491 (framepos_t) floor ( (double) where * tr->speed()));
4493 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4494 RegionView* rv = rtv->view()->find_view (*i);
4505 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4507 const TrackViewList* tracks;
4510 tracks = &track_views;
4515 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4516 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4518 boost::shared_ptr<Track> tr;
4519 boost::shared_ptr<Playlist> pl;
4521 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4523 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4524 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4526 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4528 RegionView* rv = rtv->view()->find_view (*i);
4539 /** Get regions using the following method:
4541 * Make a region list using:
4542 * (a) any selected regions
4543 * (b) the intersection of any selected tracks and the edit point(*)
4544 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4546 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4548 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4552 Editor::get_regions_from_selection_and_edit_point ()
4554 RegionSelection regions;
4556 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4557 regions.add (entered_regionview);
4559 regions = selection->regions;
4562 if ( regions.empty() ) {
4563 TrackViewList tracks = selection->tracks;
4565 if (!tracks.empty()) {
4566 /* no region selected or entered, but some selected tracks:
4567 * act on all regions on the selected tracks at the edit point
4569 framepos_t const where = get_preferred_edit_position ();
4570 get_regions_at(regions, where, tracks);
4577 /** Get regions using the following method:
4579 * Make a region list using:
4580 * (a) any selected regions
4581 * (b) the intersection of any selected tracks and the edit point(*)
4582 * (c) if neither exists, then whatever region is under the mouse
4584 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4586 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4589 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4591 RegionSelection regions;
4593 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4594 regions.add (entered_regionview);
4596 regions = selection->regions;
4599 if ( regions.empty() ) {
4600 TrackViewList tracks = selection->tracks;
4602 if (!tracks.empty()) {
4603 /* no region selected or entered, but some selected tracks:
4604 * act on all regions on the selected tracks at the edit point
4606 get_regions_at(regions, pos, tracks);
4613 /** Start with regions that are selected, or the entered regionview if none are selected.
4614 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4615 * of the regions that we started with.
4619 Editor::get_regions_from_selection_and_entered ()
4621 RegionSelection regions = selection->regions;
4623 if (regions.empty() && entered_regionview) {
4624 regions.add (entered_regionview);
4631 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4633 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4635 RouteTimeAxisView* tatv;
4637 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4639 boost::shared_ptr<Playlist> pl;
4640 vector<boost::shared_ptr<Region> > results;
4642 boost::shared_ptr<Track> tr;
4644 if ((tr = tatv->track()) == 0) {
4649 if ((pl = (tr->playlist())) != 0) {
4650 if (src_comparison) {
4651 pl->get_source_equivalent_regions (region, results);
4653 pl->get_region_list_equivalent_regions (region, results);
4657 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4658 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4659 regions.push_back (marv);
4668 Editor::show_rhythm_ferret ()
4670 if (rhythm_ferret == 0) {
4671 rhythm_ferret = new RhythmFerret(*this);
4674 rhythm_ferret->set_session (_session);
4675 rhythm_ferret->show ();
4676 rhythm_ferret->present ();
4680 Editor::first_idle ()
4682 MessageDialog* dialog = 0;
4684 if (track_views.size() > 1) {
4685 dialog = new MessageDialog (
4687 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4691 ARDOUR_UI::instance()->flush_pending ();
4694 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4698 // first idle adds route children (automation tracks), so we need to redisplay here
4699 _routes->redisplay ();
4706 Editor::_idle_resize (gpointer arg)
4708 return ((Editor*)arg)->idle_resize ();
4712 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4714 if (resize_idle_id < 0) {
4715 resize_idle_id = g_idle_add (_idle_resize, this);
4716 _pending_resize_amount = 0;
4719 /* make a note of the smallest resulting height, so that we can clamp the
4720 lower limit at TimeAxisView::hSmall */
4722 int32_t min_resulting = INT32_MAX;
4724 _pending_resize_amount += h;
4725 _pending_resize_view = view;
4727 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4729 if (selection->tracks.contains (_pending_resize_view)) {
4730 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4731 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4735 if (min_resulting < 0) {
4740 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4741 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4745 /** Handle pending resizing of tracks */
4747 Editor::idle_resize ()
4749 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4751 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4752 selection->tracks.contains (_pending_resize_view)) {
4754 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4755 if (*i != _pending_resize_view) {
4756 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4761 _pending_resize_amount = 0;
4762 _group_tabs->set_dirty ();
4763 resize_idle_id = -1;
4771 ENSURE_GUI_THREAD (*this, &Editor::located);
4774 playhead_cursor->set_position (_session->audible_frame ());
4775 if (_follow_playhead && !_pending_initial_locate) {
4776 reset_x_origin_to_follow_playhead ();
4780 _pending_locate_request = false;
4781 _pending_initial_locate = false;
4785 Editor::region_view_added (RegionView *)
4787 _summary->set_background_dirty ();
4791 Editor::region_view_removed ()
4793 _summary->set_background_dirty ();
4797 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4799 TrackViewList::const_iterator j = track_views.begin ();
4800 while (j != track_views.end()) {
4801 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4802 if (rtv && rtv->route() == r) {
4813 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4817 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4818 TimeAxisView* tv = axis_view_from_route (*i);
4828 Editor::suspend_route_redisplay ()
4831 _routes->suspend_redisplay();
4836 Editor::resume_route_redisplay ()
4839 _routes->resume_redisplay();
4844 Editor::add_routes (RouteList& routes)
4846 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4848 RouteTimeAxisView *rtv;
4849 list<RouteTimeAxisView*> new_views;
4851 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4852 boost::shared_ptr<Route> route = (*x);
4854 if (route->is_auditioner() || route->is_monitor()) {
4858 DataType dt = route->input()->default_type();
4860 if (dt == ARDOUR::DataType::AUDIO) {
4861 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4862 rtv->set_route (route);
4863 } else if (dt == ARDOUR::DataType::MIDI) {
4864 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4865 rtv->set_route (route);
4867 throw unknown_type();
4870 new_views.push_back (rtv);
4871 track_views.push_back (rtv);
4873 rtv->effective_gain_display ();
4875 if (internal_editing()) {
4876 rtv->enter_internal_edit_mode ();
4878 rtv->leave_internal_edit_mode ();
4881 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4882 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4885 if (new_views.size() > 0) {
4886 _routes->routes_added (new_views);
4887 _summary->routes_added (new_views);
4890 if (show_editor_mixer_when_tracks_arrive) {
4891 show_editor_mixer (true);
4894 editor_list_button.set_sensitive (true);
4898 Editor::timeaxisview_deleted (TimeAxisView *tv)
4900 if (tv == entered_track) {
4904 if (_session && _session->deletion_in_progress()) {
4905 /* the situation is under control */
4909 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4911 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4913 _routes->route_removed (tv);
4915 TimeAxisView::Children c = tv->get_child_list ();
4916 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4917 if (entered_track == i->get()) {
4922 /* remove it from the list of track views */
4924 TrackViewList::iterator i;
4926 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4927 i = track_views.erase (i);
4930 /* update whatever the current mixer strip is displaying, if revelant */
4932 boost::shared_ptr<Route> route;
4935 route = rtav->route ();
4938 if (current_mixer_strip && current_mixer_strip->route() == route) {
4940 TimeAxisView* next_tv;
4942 if (track_views.empty()) {
4944 } else if (i == track_views.end()) {
4945 next_tv = track_views.front();
4952 set_selected_mixer_strip (*next_tv);
4954 /* make the editor mixer strip go away setting the
4955 * button to inactive (which also unticks the menu option)
4958 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4964 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4966 if (apply_to_selection) {
4967 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4969 TrackSelection::iterator j = i;
4972 hide_track_in_display (*i, false);
4977 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4979 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4980 // this will hide the mixer strip
4981 set_selected_mixer_strip (*tv);
4984 _routes->hide_track_in_display (*tv);
4989 Editor::sync_track_view_list_and_routes ()
4991 track_views = TrackViewList (_routes->views ());
4993 _summary->set_dirty ();
4994 _group_tabs->set_dirty ();
4996 return false; // do not call again (until needed)
5000 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5002 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5007 /** Find a RouteTimeAxisView by the ID of its route */
5009 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5011 RouteTimeAxisView* v;
5013 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5014 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5015 if(v->route()->id() == id) {
5025 Editor::fit_route_group (RouteGroup *g)
5027 TrackViewList ts = axis_views_from_routes (g->route_list ());
5032 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5034 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5037 _session->cancel_audition ();
5041 if (_session->is_auditioning()) {
5042 _session->cancel_audition ();
5043 if (r == last_audition_region) {
5048 _session->audition_region (r);
5049 last_audition_region = r;
5054 Editor::hide_a_region (boost::shared_ptr<Region> r)
5056 r->set_hidden (true);
5060 Editor::show_a_region (boost::shared_ptr<Region> r)
5062 r->set_hidden (false);
5066 Editor::audition_region_from_region_list ()
5068 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5072 Editor::hide_region_from_region_list ()
5074 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5078 Editor::show_region_in_region_list ()
5080 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5084 Editor::step_edit_status_change (bool yn)
5087 start_step_editing ();
5089 stop_step_editing ();
5094 Editor::start_step_editing ()
5096 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5100 Editor::stop_step_editing ()
5102 step_edit_connection.disconnect ();
5106 Editor::check_step_edit ()
5108 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5109 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5111 mtv->check_step_edit ();
5115 return true; // do it again, till we stop
5119 Editor::scroll_press (Direction dir)
5121 ++_scroll_callbacks;
5123 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5124 /* delay the first auto-repeat */
5130 scroll_backward (1);
5138 scroll_tracks_up_line ();
5142 scroll_tracks_down_line ();
5146 /* do hacky auto-repeat */
5147 if (!_scroll_connection.connected ()) {
5149 _scroll_connection = Glib::signal_timeout().connect (
5150 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5153 _scroll_callbacks = 0;
5160 Editor::scroll_release ()
5162 _scroll_connection.disconnect ();
5165 /** Queue a change for the Editor viewport x origin to follow the playhead */
5167 Editor::reset_x_origin_to_follow_playhead ()
5169 framepos_t const frame = playhead_cursor->current_frame ();
5171 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5173 if (_session->transport_speed() < 0) {
5175 if (frame > (current_page_samples() / 2)) {
5176 center_screen (frame-(current_page_samples()/2));
5178 center_screen (current_page_samples()/2);
5185 if (frame < leftmost_frame) {
5187 if (_session->transport_rolling()) {
5188 /* rolling; end up with the playhead at the right of the page */
5189 l = frame - current_page_samples ();
5191 /* not rolling: end up with the playhead 1/4 of the way along the page */
5192 l = frame - current_page_samples() / 4;
5196 if (_session->transport_rolling()) {
5197 /* rolling: end up with the playhead on the left of the page */
5200 /* not rolling: end up with the playhead 3/4 of the way along the page */
5201 l = frame - 3 * current_page_samples() / 4;
5209 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5215 Editor::super_rapid_screen_update ()
5217 if (!_session || !_session->engine().running()) {
5221 /* METERING / MIXER STRIPS */
5223 /* update track meters, if required */
5224 if (is_mapped() && meters_running) {
5225 RouteTimeAxisView* rtv;
5226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5227 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5228 rtv->fast_update ();
5233 /* and any current mixer strip */
5234 if (current_mixer_strip) {
5235 current_mixer_strip->fast_update ();
5238 /* PLAYHEAD AND VIEWPORT */
5240 framepos_t const frame = _session->audible_frame();
5242 /* There are a few reasons why we might not update the playhead / viewport stuff:
5244 * 1. we don't update things when there's a pending locate request, otherwise
5245 * when the editor requests a locate there is a chance that this method
5246 * will move the playhead before the locate request is processed, causing
5248 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5249 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5252 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5254 last_update_frame = frame;
5256 if (!_dragging_playhead) {
5257 playhead_cursor->set_position (frame);
5260 if (!_stationary_playhead) {
5262 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5263 /* We only do this if we aren't already
5264 handling a visual change (ie if
5265 pending_visual_change.being_handled is
5266 false) so that these requests don't stack
5267 up there are too many of them to handle in
5270 reset_x_origin_to_follow_playhead ();
5275 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5279 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5280 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5281 if (target <= 0.0) {
5284 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5285 target = (target * 0.15) + (current * 0.85);
5291 set_horizontal_position (current);
5300 Editor::session_going_away ()
5302 _have_idled = false;
5304 _session_connections.drop_connections ();
5306 super_rapid_screen_update_connection.disconnect ();
5308 selection->clear ();
5309 cut_buffer->clear ();
5311 clicked_regionview = 0;
5312 clicked_axisview = 0;
5313 clicked_routeview = 0;
5314 entered_regionview = 0;
5316 last_update_frame = 0;
5319 playhead_cursor->hide ();
5321 /* rip everything out of the list displays */
5325 _route_groups->clear ();
5327 /* do this first so that deleting a track doesn't reset cms to null
5328 and thus cause a leak.
5331 if (current_mixer_strip) {
5332 if (current_mixer_strip->get_parent() != 0) {
5333 global_hpacker.remove (*current_mixer_strip);
5335 delete current_mixer_strip;
5336 current_mixer_strip = 0;
5339 /* delete all trackviews */
5341 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5344 track_views.clear ();
5346 nudge_clock->set_session (0);
5348 editor_list_button.set_active(false);
5349 editor_list_button.set_sensitive(false);
5351 /* clear tempo/meter rulers */
5352 remove_metric_marks ();
5354 clear_marker_display ();
5356 stop_step_editing ();
5358 /* get rid of any existing editor mixer strip */
5360 WindowTitle title(Glib::get_application_name());
5361 title += _("Editor");
5363 set_title (title.get_string());
5365 SessionHandlePtr::session_going_away ();
5370 Editor::show_editor_list (bool yn)
5373 _the_notebook.show ();
5375 _the_notebook.hide ();
5380 Editor::change_region_layering_order (bool from_context_menu)
5382 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5384 if (!clicked_routeview) {
5385 if (layering_order_editor) {
5386 layering_order_editor->hide ();
5391 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5397 boost::shared_ptr<Playlist> pl = track->playlist();
5403 if (layering_order_editor == 0) {
5404 layering_order_editor = new RegionLayeringOrderEditor (*this);
5407 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5408 layering_order_editor->maybe_present ();
5412 Editor::update_region_layering_order_editor ()
5414 if (layering_order_editor && layering_order_editor->is_visible ()) {
5415 change_region_layering_order (true);
5420 Editor::setup_fade_images ()
5422 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5423 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5424 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5425 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5426 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5428 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5429 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5430 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5431 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5432 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5434 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5435 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5436 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5437 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5438 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5440 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5441 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5442 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5443 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5444 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5448 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5450 Editor::action_menu_item (std::string const & name)
5452 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5455 return *manage (a->create_menu_item ());
5459 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5461 EventBox* b = manage (new EventBox);
5462 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5463 Label* l = manage (new Label (name));
5467 _the_notebook.append_page (widget, *b);
5471 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5473 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5474 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5477 if (ev->type == GDK_2BUTTON_PRESS) {
5479 /* double-click on a notebook tab shrinks or expands the notebook */
5481 if (_notebook_shrunk) {
5482 if (pre_notebook_shrink_pane_width) {
5483 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5485 _notebook_shrunk = false;
5487 pre_notebook_shrink_pane_width = edit_pane.get_position();
5489 /* this expands the LHS of the edit pane to cover the notebook
5490 PAGE but leaves the tabs visible.
5492 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5493 _notebook_shrunk = true;
5501 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5503 using namespace Menu_Helpers;
5505 MenuList& items = _control_point_context_menu.items ();
5508 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5509 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5510 if (!can_remove_control_point (item)) {
5511 items.back().set_sensitive (false);
5514 _control_point_context_menu.popup (event->button.button, event->button.time);
5518 Editor::zoom_vertical_modifier_released()
5520 _stepping_axis_view = 0;
5524 Editor::ui_parameter_changed (string parameter)
5526 if (parameter == "icon-set") {
5527 while (!_cursor_stack.empty()) {
5528 _cursor_stack.pop();
5530 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5531 } else if (parameter == "draggable-playhead") {
5532 if (_verbose_cursor) {
5533 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());