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_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_edit_mode_strings[] = {
202 static const gchar *_zoom_focus_strings[] = {
212 #ifdef USE_RUBBERBAND
213 static const gchar *_rb_opt_strings[] = {
216 N_("Balanced multitimbral mixture"),
217 N_("Unpitched percussion with stable notes"),
218 N_("Crisp monophonic instrumental"),
219 N_("Unpitched solo percussion"),
220 N_("Resample without preserving pitch"),
225 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
228 pane_size_watcher (Paned* pane)
230 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
234 Quartz: impossible to access
236 so stop that by preventing it from ever getting too narrow. 35
237 pixels is basically a rough guess at the tab width.
242 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
244 gint pos = pane->get_position ();
246 if (pos > max_width_of_lhs) {
247 pane->set_position (max_width_of_lhs);
252 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 /* time display buttons */
255 , minsec_label (_("Mins:Secs"))
256 , bbt_label (_("Bars:Beats"))
257 , timecode_label (_("Timecode"))
258 , samples_label (_("Samples"))
259 , tempo_label (_("Tempo"))
260 , meter_label (_("Meter"))
261 , mark_label (_("Location Markers"))
262 , range_mark_label (_("Range Markers"))
263 , transport_mark_label (_("Loop/Punch Ranges"))
264 , cd_mark_label (_("CD Markers"))
265 , videotl_label (_("Video Timeline"))
266 , edit_packer (4, 4, true)
268 /* the values here don't matter: layout widgets
269 reset them as needed.
272 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273 , horizontal_adjustment (0.0, 0.0, 1e16)
274 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
276 , controls_layout (unused_adjustment, vertical_adjustment)
278 /* tool bar related */
280 , toolbar_selection_clock_table (2,3)
281 , _mouse_mode_tearoff (0)
282 , automation_mode_button (_("mode"))
286 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , selection_op_cmd_depth (0)
288 , selection_op_history_it (0)
292 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293 , meters_running(false)
294 , _pending_locate_request (false)
295 , _pending_initial_locate (false)
296 , _last_cut_copy_source_track (0)
298 , _region_selection_change_updates_region_list (true)
299 , _following_mixer_selection (false)
300 , _control_point_toggled_on_press (false)
301 , _stepping_axis_view (0)
305 /* we are a singleton */
307 PublicEditor::_instance = this;
311 selection = new Selection (this);
312 cut_buffer = new Selection (this);
313 _selection_memento = new SelectionMemento ();
314 selection_op_history.clear();
317 clicked_regionview = 0;
318 clicked_axisview = 0;
319 clicked_routeview = 0;
320 clicked_control_point = 0;
321 last_update_frame = 0;
324 _drags = new DragManager (this);
327 current_mixer_strip = 0;
330 snap_type_strings = I18N (_snap_type_strings);
331 snap_mode_strings = I18N (_snap_mode_strings);
332 zoom_focus_strings = I18N (_zoom_focus_strings);
333 edit_mode_strings = I18N (_edit_mode_strings);
334 edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336 rb_opt_strings = I18N (_rb_opt_strings);
340 build_edit_mode_menu();
341 build_zoom_focus_menu();
342 build_track_count_menu();
343 build_snap_mode_menu();
344 build_snap_type_menu();
345 build_edit_point_menu();
347 snap_threshold = 5.0;
348 bbt_beat_subdivision = 4;
349 _visible_canvas_width = 0;
350 _visible_canvas_height = 0;
351 autoscroll_horizontal_allowed = false;
352 autoscroll_vertical_allowed = false;
357 current_interthread_info = 0;
358 _show_measures = true;
360 show_gain_after_trim = false;
362 have_pending_keyboard_selection = false;
363 _follow_playhead = true;
364 _stationary_playhead = false;
365 editor_ruler_menu = 0;
366 no_ruler_shown_update = false;
368 range_marker_menu = 0;
369 marker_menu_item = 0;
370 tempo_or_meter_marker_menu = 0;
371 transport_marker_menu = 0;
372 new_transport_marker_menu = 0;
373 editor_mixer_strip_width = Wide;
374 show_editor_mixer_when_tracks_arrive = false;
375 region_edit_menu_split_multichannel_item = 0;
376 region_edit_menu_split_item = 0;
379 current_stepping_trackview = 0;
381 entered_regionview = 0;
383 clear_entered_track = false;
386 button_release_can_deselect = true;
387 _dragging_playhead = false;
388 _dragging_edit_point = false;
389 select_new_marker = false;
391 layering_order_editor = 0;
392 no_save_visual = false;
394 within_track_canvas = false;
396 scrubbing_direction = 0;
400 location_marker_color = ARDOUR_UI::config()->color ("location marker");
401 location_range_color = ARDOUR_UI::config()->color ("location range");
402 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403 location_loop_color = ARDOUR_UI::config()->color ("location loop");
404 location_punch_color = ARDOUR_UI::config()->color ("location punch");
406 zoom_focus = ZoomFocusLeft;
407 _edit_point = EditAtMouse;
408 _visible_track_count = -1;
410 samples_per_pixel = 2048; /* too early to use reset_zoom () */
412 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413 TimeAxisView::setup_sizes ();
414 Marker::setup_sizes (timebar_height);
416 _scroll_callbacks = 0;
418 bbt_label.set_name ("EditorRulerLabel");
419 bbt_label.set_size_request (-1, (int)timebar_height);
420 bbt_label.set_alignment (1.0, 0.5);
421 bbt_label.set_padding (5,0);
423 bbt_label.set_no_show_all();
424 minsec_label.set_name ("EditorRulerLabel");
425 minsec_label.set_size_request (-1, (int)timebar_height);
426 minsec_label.set_alignment (1.0, 0.5);
427 minsec_label.set_padding (5,0);
428 minsec_label.hide ();
429 minsec_label.set_no_show_all();
430 timecode_label.set_name ("EditorRulerLabel");
431 timecode_label.set_size_request (-1, (int)timebar_height);
432 timecode_label.set_alignment (1.0, 0.5);
433 timecode_label.set_padding (5,0);
434 timecode_label.hide ();
435 timecode_label.set_no_show_all();
436 samples_label.set_name ("EditorRulerLabel");
437 samples_label.set_size_request (-1, (int)timebar_height);
438 samples_label.set_alignment (1.0, 0.5);
439 samples_label.set_padding (5,0);
440 samples_label.hide ();
441 samples_label.set_no_show_all();
443 tempo_label.set_name ("EditorRulerLabel");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
448 tempo_label.set_no_show_all();
450 meter_label.set_name ("EditorRulerLabel");
451 meter_label.set_size_request (-1, (int)timebar_height);
452 meter_label.set_alignment (1.0, 0.5);
453 meter_label.set_padding (5,0);
455 meter_label.set_no_show_all();
457 if (Profile->get_trx()) {
458 mark_label.set_text (_("Markers"));
460 mark_label.set_name ("EditorRulerLabel");
461 mark_label.set_size_request (-1, (int)timebar_height);
462 mark_label.set_alignment (1.0, 0.5);
463 mark_label.set_padding (5,0);
465 mark_label.set_no_show_all();
467 cd_mark_label.set_name ("EditorRulerLabel");
468 cd_mark_label.set_size_request (-1, (int)timebar_height);
469 cd_mark_label.set_alignment (1.0, 0.5);
470 cd_mark_label.set_padding (5,0);
471 cd_mark_label.hide();
472 cd_mark_label.set_no_show_all();
474 videotl_bar_height = 4;
475 videotl_label.set_name ("EditorRulerLabel");
476 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477 videotl_label.set_alignment (1.0, 0.5);
478 videotl_label.set_padding (5,0);
479 videotl_label.hide();
480 videotl_label.set_no_show_all();
482 range_mark_label.set_name ("EditorRulerLabel");
483 range_mark_label.set_size_request (-1, (int)timebar_height);
484 range_mark_label.set_alignment (1.0, 0.5);
485 range_mark_label.set_padding (5,0);
486 range_mark_label.hide();
487 range_mark_label.set_no_show_all();
489 transport_mark_label.set_name ("EditorRulerLabel");
490 transport_mark_label.set_size_request (-1, (int)timebar_height);
491 transport_mark_label.set_alignment (1.0, 0.5);
492 transport_mark_label.set_padding (5,0);
493 transport_mark_label.hide();
494 transport_mark_label.set_no_show_all();
496 initialize_canvas ();
498 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
500 _summary = new EditorSummary (this);
502 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
505 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
507 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
510 edit_controls_vbox.set_spacing (0);
511 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
514 HBox* h = manage (new HBox);
515 _group_tabs = new EditorGroupTabs (this);
516 if (!ARDOUR::Profile->get_trx()) {
517 h->pack_start (*_group_tabs, PACK_SHRINK);
519 h->pack_start (edit_controls_vbox);
520 controls_layout.add (*h);
522 controls_layout.set_name ("EditControlsBase");
523 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
527 _cursors = new MouseCursors;
528 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
531 /* Push default cursor to ever-present bottom of cursor stack. */
532 push_canvas_cursor(_cursors->grabber);
534 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
536 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538 pad_line_1->set_outline_color (0xFF0000FF);
544 edit_packer.set_col_spacings (0);
545 edit_packer.set_row_spacings (0);
546 edit_packer.set_homogeneous (false);
547 edit_packer.set_border_width (0);
548 edit_packer.set_name ("EditorWindow");
550 time_bars_event_box.add (time_bars_vbox);
551 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
554 /* labels for the time bars */
555 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
557 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
559 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
561 bottom_hbox.set_border_width (2);
562 bottom_hbox.set_spacing (3);
564 _route_groups = new EditorRouteGroups (this);
565 _routes = new EditorRoutes (this);
566 _regions = new EditorRegions (this);
567 _snapshots = new EditorSnapshots (this);
568 _locations = new EditorLocations (this);
570 /* these are static location signals */
572 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
576 add_notebook_page (_("Regions"), _regions->widget ());
577 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578 add_notebook_page (_("Snapshots"), _snapshots->widget ());
579 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
582 _the_notebook.set_show_tabs (true);
583 _the_notebook.set_scrollable (true);
584 _the_notebook.popup_disable ();
585 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586 _the_notebook.show_all ();
588 _notebook_shrunk = false;
590 editor_summary_pane.pack1(edit_packer);
592 Button* summary_arrows_left_left = manage (new Button);
593 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_left_right = manage (new Button);
598 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_left = manage (new VBox);
603 summary_arrows_left->pack_start (*summary_arrows_left_left);
604 summary_arrows_left->pack_start (*summary_arrows_left_right);
606 Button* summary_arrows_right_up = manage (new Button);
607 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
611 Button* summary_arrows_right_down = manage (new Button);
612 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
616 VBox* summary_arrows_right = manage (new VBox);
617 summary_arrows_right->pack_start (*summary_arrows_right_up);
618 summary_arrows_right->pack_start (*summary_arrows_right_down);
620 Frame* summary_frame = manage (new Frame);
621 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
623 summary_frame->add (*_summary);
624 summary_frame->show ();
626 _summary_hbox.pack_start (*summary_arrows_left, false, false);
627 _summary_hbox.pack_start (*summary_frame, true, true);
628 _summary_hbox.pack_start (*summary_arrows_right, false, false);
630 if (!ARDOUR::Profile->get_trx()) {
631 editor_summary_pane.pack2 (_summary_hbox);
634 edit_pane.pack1 (editor_summary_pane, true, true);
635 if (!ARDOUR::Profile->get_trx()) {
636 edit_pane.pack2 (_the_notebook, false, true);
639 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
641 /* XXX: editor_summary_pane might need similar to the edit_pane */
643 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
645 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
648 top_hbox.pack_start (toolbar_frame);
650 HBox *hbox = manage (new HBox);
651 hbox->pack_start (edit_pane, true, true);
653 global_vpacker.pack_start (top_hbox, false, false);
654 global_vpacker.pack_start (*hbox, true, true);
656 global_hpacker.pack_start (global_vpacker, true, true);
658 set_name ("EditorWindow");
659 add_accel_group (ActionManager::ui_manager->get_accel_group());
661 status_bar_hpacker.show ();
663 vpacker.pack_end (status_bar_hpacker, false, false);
664 vpacker.pack_end (global_hpacker, true, true);
666 /* register actions now so that set_state() can find them and set toggles/checks etc */
669 /* when we start using our own keybinding system for the editor, this
670 * will be uncommented
676 set_zoom_focus (zoom_focus);
677 set_visible_track_count (_visible_track_count);
678 _snap_type = SnapToBeat;
679 set_snap_to (_snap_type);
680 _snap_mode = SnapOff;
681 set_snap_mode (_snap_mode);
682 set_mouse_mode (MouseObject, true);
683 pre_internal_snap_type = _snap_type;
684 pre_internal_snap_mode = _snap_mode;
685 internal_snap_type = _snap_type;
686 internal_snap_mode = _snap_mode;
687 set_edit_point_preference (EditAtMouse, true);
689 _playlist_selector = new PlaylistSelector();
690 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
692 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
696 nudge_forward_button.set_name ("nudge button");
697 nudge_forward_button.set_image(::get_icon("nudge_right"));
699 nudge_backward_button.set_name ("nudge button");
700 nudge_backward_button.set_image(::get_icon("nudge_left"));
702 fade_context_menu.set_name ("ArdourContextMenu");
704 /* icons, titles, WM stuff */
706 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
707 Glib::RefPtr<Gdk::Pixbuf> icon;
709 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
710 window_icons.push_back (icon);
712 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
713 window_icons.push_back (icon);
715 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
716 window_icons.push_back (icon);
718 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
719 window_icons.push_back (icon);
721 if (!window_icons.empty()) {
722 // set_icon_list (window_icons);
723 set_default_icon_list (window_icons);
726 WindowTitle title(Glib::get_application_name());
727 title += _("Editor");
728 set_title (title.get_string());
729 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
732 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
734 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
735 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
737 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
739 /* allow external control surfaces/protocols to do various things */
741 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
742 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
743 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
744 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
745 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
746 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
747 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
748 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
749 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
750 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
751 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
752 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
753 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
754 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
756 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
757 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
758 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
759 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
760 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
762 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
764 /* problematic: has to return a value and thus cannot be x-thread */
766 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
768 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
769 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
771 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
773 _ignore_region_action = false;
774 _last_region_menu_was_main = false;
775 _popup_region_menu_item = 0;
777 _ignore_follow_edits = false;
779 _show_marker_lines = false;
781 /* Button bindings */
783 button_bindings = new Bindings;
785 XMLNode* node = button_settings();
787 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
788 button_bindings->load (**i);
794 /* grab current parameter state */
795 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
796 ARDOUR_UI::config()->map_parameters (pc);
798 setup_fade_images ();
805 delete button_bindings;
807 delete _route_groups;
808 delete _track_canvas_viewport;
814 Editor::button_settings () const
816 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
817 XMLNode* node = find_named_node (*settings, X_("Buttons"));
820 node = new XMLNode (X_("Buttons"));
827 Editor::add_toplevel_menu (Container& cont)
829 vpacker.pack_start (cont, false, false);
834 Editor::add_transport_frame (Container& cont)
836 if(ARDOUR::Profile->get_mixbus()) {
837 global_vpacker.pack_start (cont, false, false);
838 global_vpacker.reorder_child (cont, 0);
841 vpacker.pack_start (cont, false, false);
846 Editor::get_smart_mode () const
848 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
852 Editor::catch_vanishing_regionview (RegionView *rv)
854 /* note: the selection will take care of the vanishing
855 audioregionview by itself.
858 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
862 if (clicked_regionview == rv) {
863 clicked_regionview = 0;
866 if (entered_regionview == rv) {
867 set_entered_regionview (0);
870 if (!_all_region_actions_sensitized) {
871 sensitize_all_region_actions (true);
876 Editor::set_entered_regionview (RegionView* rv)
878 if (rv == entered_regionview) {
882 if (entered_regionview) {
883 entered_regionview->exited ();
886 entered_regionview = rv;
888 if (entered_regionview != 0) {
889 entered_regionview->entered ();
892 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
893 /* This RegionView entry might have changed what region actions
894 are allowed, so sensitize them all in case a key is pressed.
896 sensitize_all_region_actions (true);
901 Editor::set_entered_track (TimeAxisView* tav)
904 entered_track->exited ();
910 entered_track->entered ();
915 Editor::show_window ()
917 if (!is_visible ()) {
921 /* XXX: this is a bit unfortunate; it would probably
922 be nicer if we could just call show () above rather
923 than needing the show_all ()
926 /* re-hide stuff if necessary */
927 editor_list_button_toggled ();
928 parameter_changed ("show-summary");
929 parameter_changed ("show-group-tabs");
930 parameter_changed ("show-zoom-tools");
932 /* now reset all audio_time_axis heights, because widgets might need
938 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
939 tv = (static_cast<TimeAxisView*>(*i));
943 if (current_mixer_strip) {
944 current_mixer_strip->hide_things ();
945 current_mixer_strip->parameter_changed ("mixer-element-visibility");
953 Editor::instant_save ()
955 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
960 _session->add_instant_xml(get_state());
962 Config->add_instant_xml(get_state());
967 Editor::control_vertical_zoom_in_all ()
969 tav_zoom_smooth (false, true);
973 Editor::control_vertical_zoom_out_all ()
975 tav_zoom_smooth (true, true);
979 Editor::control_vertical_zoom_in_selected ()
981 tav_zoom_smooth (false, false);
985 Editor::control_vertical_zoom_out_selected ()
987 tav_zoom_smooth (true, false);
991 Editor::control_view (uint32_t view)
993 goto_visual_state (view);
997 Editor::control_unselect ()
999 selection->clear_tracks ();
1003 Editor::control_select (uint32_t rid, Selection::Operation op)
1005 /* handles the (static) signal from the ControlProtocol class that
1006 * requests setting the selected track to a given RID
1013 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1019 TimeAxisView* tav = axis_view_from_route (r);
1023 case Selection::Add:
1024 selection->add (tav);
1026 case Selection::Toggle:
1027 selection->toggle (tav);
1029 case Selection::Extend:
1031 case Selection::Set:
1032 selection->set (tav);
1036 selection->clear_tracks ();
1041 Editor::control_step_tracks_up ()
1043 scroll_tracks_up_line ();
1047 Editor::control_step_tracks_down ()
1049 scroll_tracks_down_line ();
1053 Editor::control_scroll (float fraction)
1055 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1061 double step = fraction * current_page_samples();
1064 _control_scroll_target is an optional<T>
1066 it acts like a pointer to an framepos_t, with
1067 a operator conversion to boolean to check
1068 that it has a value could possibly use
1069 playhead_cursor->current_frame to store the
1070 value and a boolean in the class to know
1071 when it's out of date
1074 if (!_control_scroll_target) {
1075 _control_scroll_target = _session->transport_frame();
1076 _dragging_playhead = true;
1079 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1080 *_control_scroll_target = 0;
1081 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1082 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1084 *_control_scroll_target += (framepos_t) trunc (step);
1087 /* move visuals, we'll catch up with it later */
1089 playhead_cursor->set_position (*_control_scroll_target);
1090 UpdateAllTransportClocks (*_control_scroll_target);
1092 if (*_control_scroll_target > (current_page_samples() / 2)) {
1093 /* try to center PH in window */
1094 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1100 Now we do a timeout to actually bring the session to the right place
1101 according to the playhead. This is to avoid reading disk buffers on every
1102 call to control_scroll, which is driven by ScrollTimeline and therefore
1103 probably by a control surface wheel which can generate lots of events.
1105 /* cancel the existing timeout */
1107 control_scroll_connection.disconnect ();
1109 /* add the next timeout */
1111 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1115 Editor::deferred_control_scroll (framepos_t /*target*/)
1117 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1118 // reset for next stream
1119 _control_scroll_target = boost::none;
1120 _dragging_playhead = false;
1125 Editor::access_action (std::string action_group, std::string action_item)
1131 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1134 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1142 Editor::on_realize ()
1144 Window::on_realize ();
1147 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1148 start_lock_event_timing ();
1151 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1155 Editor::start_lock_event_timing ()
1157 /* check if we should lock the GUI every 30 seconds */
1159 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1163 Editor::generic_event_handler (GdkEvent* ev)
1166 case GDK_BUTTON_PRESS:
1167 case GDK_BUTTON_RELEASE:
1168 case GDK_MOTION_NOTIFY:
1170 case GDK_KEY_RELEASE:
1171 gettimeofday (&last_event_time, 0);
1174 case GDK_LEAVE_NOTIFY:
1175 switch (ev->crossing.detail) {
1176 case GDK_NOTIFY_UNKNOWN:
1177 case GDK_NOTIFY_INFERIOR:
1178 case GDK_NOTIFY_ANCESTOR:
1180 case GDK_NOTIFY_VIRTUAL:
1181 case GDK_NOTIFY_NONLINEAR:
1182 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1183 /* leaving window, so reset focus, thus ending any and
1184 all text entry operations.
1199 Editor::lock_timeout_callback ()
1201 struct timeval now, delta;
1203 gettimeofday (&now, 0);
1205 timersub (&now, &last_event_time, &delta);
1207 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1209 /* don't call again. Returning false will effectively
1210 disconnect us from the timer callback.
1212 unlock() will call start_lock_event_timing() to get things
1222 Editor::map_position_change (framepos_t frame)
1224 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1226 if (_session == 0) {
1230 if (_follow_playhead) {
1231 center_screen (frame);
1234 playhead_cursor->set_position (frame);
1238 Editor::center_screen (framepos_t frame)
1240 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1242 /* if we're off the page, then scroll.
1245 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1246 center_screen_internal (frame, page);
1251 Editor::center_screen_internal (framepos_t frame, float page)
1256 frame -= (framepos_t) page;
1261 reset_x_origin (frame);
1266 Editor::update_title ()
1268 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1271 bool dirty = _session->dirty();
1273 string session_name;
1275 if (_session->snap_name() != _session->name()) {
1276 session_name = _session->snap_name();
1278 session_name = _session->name();
1282 session_name = "*" + session_name;
1285 WindowTitle title(session_name);
1286 title += Glib::get_application_name();
1287 set_title (title.get_string());
1289 /* ::session_going_away() will have taken care of it */
1294 Editor::set_session (Session *t)
1296 SessionHandlePtr::set_session (t);
1302 _playlist_selector->set_session (_session);
1303 nudge_clock->set_session (_session);
1304 _summary->set_session (_session);
1305 _group_tabs->set_session (_session);
1306 _route_groups->set_session (_session);
1307 _regions->set_session (_session);
1308 _snapshots->set_session (_session);
1309 _routes->set_session (_session);
1310 _locations->set_session (_session);
1312 if (rhythm_ferret) {
1313 rhythm_ferret->set_session (_session);
1316 if (analysis_window) {
1317 analysis_window->set_session (_session);
1321 sfbrowser->set_session (_session);
1324 compute_fixed_ruler_scale ();
1326 /* Make sure we have auto loop and auto punch ranges */
1328 Location* loc = _session->locations()->auto_loop_location();
1330 loc->set_name (_("Loop"));
1333 loc = _session->locations()->auto_punch_location();
1336 loc->set_name (_("Punch"));
1339 refresh_location_display ();
1341 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1342 the selected Marker; this needs the LocationMarker list to be available.
1344 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1345 set_state (*node, Stateful::loading_state_version);
1347 /* catch up with the playhead */
1349 _session->request_locate (playhead_cursor->current_frame ());
1350 _pending_initial_locate = true;
1354 /* These signals can all be emitted by a non-GUI thread. Therefore the
1355 handlers for them must not attempt to directly interact with the GUI,
1356 but use PBD::Signal<T>::connect() which accepts an event loop
1357 ("context") where the handler will be asked to run.
1360 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1361 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1362 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1363 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1364 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1365 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1366 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1367 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1368 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1369 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1370 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1371 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1372 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1374 playhead_cursor->show ();
1376 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1377 Config->map_parameters (pc);
1378 _session->config.map_parameters (pc);
1380 restore_ruler_visibility ();
1381 //tempo_map_changed (PropertyChange (0));
1382 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1384 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1385 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1388 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1389 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1392 switch (_snap_type) {
1393 case SnapToRegionStart:
1394 case SnapToRegionEnd:
1395 case SnapToRegionSync:
1396 case SnapToRegionBoundary:
1397 build_region_boundary_cache ();
1404 /* register for undo history */
1405 _session->register_with_memento_command_factory(id(), this);
1406 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1408 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1410 start_updating_meters ();
1414 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1416 if (a->get_name() == "RegionMenu") {
1417 /* When the main menu's region menu is opened, we setup the actions so that they look right
1418 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1419 so we resensitize all region actions when the entered regionview or the region selection
1420 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1421 happens after the region context menu is opened. So we set a flag here, too.
1425 sensitize_the_right_region_actions ();
1426 _last_region_menu_was_main = true;
1431 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1433 using namespace Menu_Helpers;
1435 void (Editor::*emf)(FadeShape);
1436 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1439 images = &_xfade_in_images;
1440 emf = &Editor::set_fade_in_shape;
1442 images = &_xfade_out_images;
1443 emf = &Editor::set_fade_out_shape;
1448 _("Linear (for highly correlated material)"),
1449 *(*images)[FadeLinear],
1450 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1458 _("Constant power"),
1459 *(*images)[FadeConstantPower],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1463 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1468 *(*images)[FadeSymmetric],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeSlow],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeFast],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 /** Pop up a context menu for when the user clicks on a start crossfade */
1496 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1498 using namespace Menu_Helpers;
1499 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1504 MenuList& items (xfade_in_context_menu.items());
1507 if (arv->audio_region()->fade_in_active()) {
1508 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1510 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1513 items.push_back (SeparatorElem());
1514 fill_xfade_menu (items, true);
1516 xfade_in_context_menu.popup (button, time);
1519 /** Pop up a context menu for when the user clicks on an end crossfade */
1521 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1523 using namespace Menu_Helpers;
1524 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1529 MenuList& items (xfade_out_context_menu.items());
1532 if (arv->audio_region()->fade_out_active()) {
1533 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1535 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1538 items.push_back (SeparatorElem());
1539 fill_xfade_menu (items, false);
1541 xfade_out_context_menu.popup (button, time);
1545 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1547 using namespace Menu_Helpers;
1548 Menu* (Editor::*build_menu_function)();
1551 switch (item_type) {
1553 case RegionViewName:
1554 case RegionViewNameHighlight:
1555 case LeftFrameHandle:
1556 case RightFrameHandle:
1557 if (with_selection) {
1558 build_menu_function = &Editor::build_track_selection_context_menu;
1560 build_menu_function = &Editor::build_track_region_context_menu;
1565 if (with_selection) {
1566 build_menu_function = &Editor::build_track_selection_context_menu;
1568 build_menu_function = &Editor::build_track_context_menu;
1573 if (clicked_routeview->track()) {
1574 build_menu_function = &Editor::build_track_context_menu;
1576 build_menu_function = &Editor::build_track_bus_context_menu;
1581 /* probably shouldn't happen but if it does, we don't care */
1585 menu = (this->*build_menu_function)();
1586 menu->set_name ("ArdourContextMenu");
1588 /* now handle specific situations */
1590 switch (item_type) {
1592 case RegionViewName:
1593 case RegionViewNameHighlight:
1594 case LeftFrameHandle:
1595 case RightFrameHandle:
1596 if (!with_selection) {
1597 if (region_edit_menu_split_item) {
1598 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1599 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1601 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1604 if (region_edit_menu_split_multichannel_item) {
1605 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1606 region_edit_menu_split_multichannel_item->set_sensitive (true);
1608 region_edit_menu_split_multichannel_item->set_sensitive (false);
1621 /* probably shouldn't happen but if it does, we don't care */
1625 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1627 /* Bounce to disk */
1629 using namespace Menu_Helpers;
1630 MenuList& edit_items = menu->items();
1632 edit_items.push_back (SeparatorElem());
1634 switch (clicked_routeview->audio_track()->freeze_state()) {
1635 case AudioTrack::NoFreeze:
1636 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1639 case AudioTrack::Frozen:
1640 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1643 case AudioTrack::UnFrozen:
1644 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1650 if (item_type == StreamItem && clicked_routeview) {
1651 clicked_routeview->build_underlay_menu(menu);
1654 /* When the region menu is opened, we setup the actions so that they look right
1657 sensitize_the_right_region_actions ();
1658 _last_region_menu_was_main = false;
1660 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1661 menu->popup (button, time);
1665 Editor::build_track_context_menu ()
1667 using namespace Menu_Helpers;
1669 MenuList& edit_items = track_context_menu.items();
1672 add_dstream_context_items (edit_items);
1673 return &track_context_menu;
1677 Editor::build_track_bus_context_menu ()
1679 using namespace Menu_Helpers;
1681 MenuList& edit_items = track_context_menu.items();
1684 add_bus_context_items (edit_items);
1685 return &track_context_menu;
1689 Editor::build_track_region_context_menu ()
1691 using namespace Menu_Helpers;
1692 MenuList& edit_items = track_region_context_menu.items();
1695 /* we've just cleared the track region context menu, so the menu that these
1696 two items were on will have disappeared; stop them dangling.
1698 region_edit_menu_split_item = 0;
1699 region_edit_menu_split_multichannel_item = 0;
1701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1704 boost::shared_ptr<Track> tr;
1705 boost::shared_ptr<Playlist> pl;
1707 if ((tr = rtv->track())) {
1708 add_region_context_items (edit_items, tr);
1712 add_dstream_context_items (edit_items);
1714 return &track_region_context_menu;
1718 Editor::analyze_region_selection ()
1720 if (analysis_window == 0) {
1721 analysis_window = new AnalysisWindow();
1724 analysis_window->set_session(_session);
1726 analysis_window->show_all();
1729 analysis_window->set_regionmode();
1730 analysis_window->analyze();
1732 analysis_window->present();
1736 Editor::analyze_range_selection()
1738 if (analysis_window == 0) {
1739 analysis_window = new AnalysisWindow();
1742 analysis_window->set_session(_session);
1744 analysis_window->show_all();
1747 analysis_window->set_rangemode();
1748 analysis_window->analyze();
1750 analysis_window->present();
1754 Editor::build_track_selection_context_menu ()
1756 using namespace Menu_Helpers;
1757 MenuList& edit_items = track_selection_context_menu.items();
1758 edit_items.clear ();
1760 add_selection_context_items (edit_items);
1761 // edit_items.push_back (SeparatorElem());
1762 // add_dstream_context_items (edit_items);
1764 return &track_selection_context_menu;
1768 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1770 using namespace Menu_Helpers;
1772 /* OK, stick the region submenu at the top of the list, and then add
1776 RegionSelection rs = get_regions_from_selection_and_entered ();
1778 string::size_type pos = 0;
1779 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1781 /* we have to hack up the region name because "_" has a special
1782 meaning for menu titles.
1785 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1786 menu_item_name.replace (pos, 1, "__");
1790 if (_popup_region_menu_item == 0) {
1791 _popup_region_menu_item = new MenuItem (menu_item_name);
1792 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1793 _popup_region_menu_item->show ();
1795 _popup_region_menu_item->set_label (menu_item_name);
1798 const framepos_t position = get_preferred_edit_position (false, true);
1800 edit_items.push_back (*_popup_region_menu_item);
1801 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1802 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1804 edit_items.push_back (SeparatorElem());
1807 /** Add context menu items relevant to selection ranges.
1808 * @param edit_items List to add the items to.
1811 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1813 using namespace Menu_Helpers;
1815 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1816 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1818 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1821 edit_items.push_back (SeparatorElem());
1822 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1824 edit_items.push_back (SeparatorElem());
1826 edit_items.push_back (
1828 _("Move Range Start to Previous Region Boundary"),
1829 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1833 edit_items.push_back (
1835 _("Move Range Start to Next Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1840 edit_items.push_back (
1842 _("Move Range End to Previous Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1847 edit_items.push_back (
1849 _("Move Range End to Next Region Boundary"),
1850 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1854 edit_items.push_back (SeparatorElem());
1855 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1856 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1863 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1864 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1869 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1871 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1872 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1876 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1877 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1878 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1879 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1880 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1881 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1887 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1889 using namespace Menu_Helpers;
1893 Menu *play_menu = manage (new Menu);
1894 MenuList& play_items = play_menu->items();
1895 play_menu->set_name ("ArdourContextMenu");
1897 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1898 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1899 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1900 play_items.push_back (SeparatorElem());
1901 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1903 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1907 Menu *select_menu = manage (new Menu);
1908 MenuList& select_items = select_menu->items();
1909 select_menu->set_name ("ArdourContextMenu");
1911 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1912 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1914 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1915 select_items.push_back (SeparatorElem());
1916 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1917 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1918 select_items.push_back (SeparatorElem());
1919 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1920 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1921 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1922 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1923 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1924 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1925 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
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 cutnpaste_items.push_back (SeparatorElem());
1941 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1942 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1944 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1946 /* Adding new material */
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1950 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1954 Menu *nudge_menu = manage (new Menu());
1955 MenuList& nudge_items = nudge_menu->items();
1956 nudge_menu->set_name ("ArdourContextMenu");
1958 edit_items.push_back (SeparatorElem());
1959 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1960 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1962 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1964 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1968 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1970 using namespace Menu_Helpers;
1974 Menu *play_menu = manage (new Menu);
1975 MenuList& play_items = play_menu->items();
1976 play_menu->set_name ("ArdourContextMenu");
1978 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1979 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1980 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1984 Menu *select_menu = manage (new Menu);
1985 MenuList& select_items = select_menu->items();
1986 select_menu->set_name ("ArdourContextMenu");
1988 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1989 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1991 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1992 select_items.push_back (SeparatorElem());
1993 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1994 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1995 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1996 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1998 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2002 Menu *cutnpaste_menu = manage (new Menu);
2003 MenuList& cutnpaste_items = cutnpaste_menu->items();
2004 cutnpaste_menu->set_name ("ArdourContextMenu");
2006 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2007 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2008 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2010 Menu *nudge_menu = manage (new Menu());
2011 MenuList& nudge_items = nudge_menu->items();
2012 nudge_menu->set_name ("ArdourContextMenu");
2014 edit_items.push_back (SeparatorElem());
2015 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2018 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2020 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2024 Editor::snap_type() const
2030 Editor::snap_mode() const
2036 Editor::set_snap_to (SnapType st)
2038 unsigned int snap_ind = (unsigned int)st;
2040 if (internal_editing()) {
2041 internal_snap_type = st;
2043 pre_internal_snap_type = st;
2048 if (snap_ind > snap_type_strings.size() - 1) {
2050 _snap_type = (SnapType)snap_ind;
2053 string str = snap_type_strings[snap_ind];
2055 if (str != snap_type_selector.get_text()) {
2056 snap_type_selector.set_text (str);
2061 switch (_snap_type) {
2062 case SnapToBeatDiv128:
2063 case SnapToBeatDiv64:
2064 case SnapToBeatDiv32:
2065 case SnapToBeatDiv28:
2066 case SnapToBeatDiv24:
2067 case SnapToBeatDiv20:
2068 case SnapToBeatDiv16:
2069 case SnapToBeatDiv14:
2070 case SnapToBeatDiv12:
2071 case SnapToBeatDiv10:
2072 case SnapToBeatDiv8:
2073 case SnapToBeatDiv7:
2074 case SnapToBeatDiv6:
2075 case SnapToBeatDiv5:
2076 case SnapToBeatDiv4:
2077 case SnapToBeatDiv3:
2078 case SnapToBeatDiv2: {
2079 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2080 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2082 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2083 current_bbt_points_begin, current_bbt_points_end);
2084 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2085 current_bbt_points_begin, current_bbt_points_end);
2086 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2090 case SnapToRegionStart:
2091 case SnapToRegionEnd:
2092 case SnapToRegionSync:
2093 case SnapToRegionBoundary:
2094 build_region_boundary_cache ();
2102 redisplay_tempo (false);
2104 SnapChanged (); /* EMIT SIGNAL */
2108 Editor::set_snap_mode (SnapMode mode)
2110 string str = snap_mode_strings[(int)mode];
2112 if (internal_editing()) {
2113 internal_snap_mode = mode;
2115 pre_internal_snap_mode = mode;
2120 if (str != snap_mode_selector.get_text ()) {
2121 snap_mode_selector.set_text (str);
2127 Editor::set_edit_point_preference (EditPoint ep, bool force)
2129 bool changed = (_edit_point != ep);
2132 if (Profile->get_mixbus())
2133 if (ep == EditAtSelectedMarker)
2134 ep = EditAtPlayhead;
2136 string str = edit_point_strings[(int)ep];
2137 if (str != edit_point_selector.get_text ()) {
2138 edit_point_selector.set_text (str);
2141 update_all_enter_cursors();
2143 if (!force && !changed) {
2147 const char* action=NULL;
2149 switch (_edit_point) {
2150 case EditAtPlayhead:
2151 action = "edit-at-playhead";
2153 case EditAtSelectedMarker:
2154 action = "edit-at-marker";
2157 action = "edit-at-mouse";
2161 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2163 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2167 bool in_track_canvas;
2169 if (!mouse_frame (foo, in_track_canvas)) {
2170 in_track_canvas = false;
2173 reset_canvas_action_sensitivity (in_track_canvas);
2179 Editor::set_state (const XMLNode& node, int /*version*/)
2181 const XMLProperty* prop;
2188 g.base_width = default_width;
2189 g.base_height = default_height;
2193 if ((geometry = find_named_node (node, "geometry")) != 0) {
2197 if ((prop = geometry->property("x_size")) == 0) {
2198 prop = geometry->property ("x-size");
2201 g.base_width = atoi(prop->value());
2203 if ((prop = geometry->property("y_size")) == 0) {
2204 prop = geometry->property ("y-size");
2207 g.base_height = atoi(prop->value());
2210 if ((prop = geometry->property ("x_pos")) == 0) {
2211 prop = geometry->property ("x-pos");
2214 x = atoi (prop->value());
2217 if ((prop = geometry->property ("y_pos")) == 0) {
2218 prop = geometry->property ("y-pos");
2221 y = atoi (prop->value());
2225 set_default_size (g.base_width, g.base_height);
2228 if (_session && (prop = node.property ("playhead"))) {
2230 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2232 playhead_cursor->set_position (pos);
2234 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2235 playhead_cursor->set_position (0);
2238 playhead_cursor->set_position (0);
2241 if ((prop = node.property ("mixer-width"))) {
2242 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2245 if ((prop = node.property ("zoom-focus"))) {
2246 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2249 if ((prop = node.property ("zoom"))) {
2250 /* older versions of ardour used floating point samples_per_pixel */
2251 double f = PBD::atof (prop->value());
2252 reset_zoom (llrintf (f));
2254 reset_zoom (samples_per_pixel);
2257 if ((prop = node.property ("visible-track-count"))) {
2258 set_visible_track_count (PBD::atoi (prop->value()));
2261 if ((prop = node.property ("snap-to"))) {
2262 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2265 if ((prop = node.property ("snap-mode"))) {
2266 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2269 if ((prop = node.property ("internal-snap-to"))) {
2270 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2273 if ((prop = node.property ("internal-snap-mode"))) {
2274 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2277 if ((prop = node.property ("pre-internal-snap-to"))) {
2278 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2281 if ((prop = node.property ("pre-internal-snap-mode"))) {
2282 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2285 if ((prop = node.property ("mouse-mode"))) {
2286 MouseMode m = str2mousemode(prop->value());
2287 set_mouse_mode (m, true);
2289 set_mouse_mode (MouseObject, true);
2292 if ((prop = node.property ("left-frame")) != 0) {
2294 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2298 reset_x_origin (pos);
2302 if ((prop = node.property ("y-origin")) != 0) {
2303 reset_y_origin (atof (prop->value ()));
2306 if ((prop = node.property ("join-object-range"))) {
2307 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2308 bool yn = string_is_affirmative (prop->value());
2310 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2311 tact->set_active (!yn);
2312 tact->set_active (yn);
2314 set_mouse_mode(mouse_mode, true);
2317 if ((prop = node.property ("edit-point"))) {
2318 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2321 if ((prop = node.property ("show-measures"))) {
2322 bool yn = string_is_affirmative (prop->value());
2323 _show_measures = yn;
2324 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2326 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2327 /* do it twice to force the change */
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2333 if ((prop = node.property ("follow-playhead"))) {
2334 bool yn = string_is_affirmative (prop->value());
2335 set_follow_playhead (yn);
2336 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2338 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2339 if (tact->get_active() != yn) {
2340 tact->set_active (yn);
2345 if ((prop = node.property ("stationary-playhead"))) {
2346 bool yn = string_is_affirmative (prop->value());
2347 set_stationary_playhead (yn);
2348 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2350 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2351 if (tact->get_active() != yn) {
2352 tact->set_active (yn);
2357 if ((prop = node.property ("region-list-sort-type"))) {
2358 RegionListSortType st;
2359 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2362 if ((prop = node.property ("show-editor-mixer"))) {
2364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368 bool yn = string_is_affirmative (prop->value());
2370 /* do it twice to force the change */
2372 tact->set_active (!yn);
2373 tact->set_active (yn);
2376 if ((prop = node.property ("show-editor-list"))) {
2378 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2381 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2382 bool yn = string_is_affirmative (prop->value());
2384 /* do it twice to force the change */
2386 tact->set_active (!yn);
2387 tact->set_active (yn);
2390 if ((prop = node.property (X_("editor-list-page")))) {
2391 _the_notebook.set_current_page (atoi (prop->value ()));
2394 if ((prop = node.property (X_("show-marker-lines")))) {
2395 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2397 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2398 bool yn = string_is_affirmative (prop->value ());
2400 tact->set_active (!yn);
2401 tact->set_active (yn);
2404 XMLNodeList children = node.children ();
2405 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2406 selection->set_state (**i, Stateful::current_state_version);
2407 _regions->set_state (**i);
2410 if ((prop = node.property ("maximised"))) {
2411 bool yn = string_is_affirmative (prop->value());
2412 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2414 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2415 bool fs = tact && tact->get_active();
2417 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2421 if ((prop = node.property ("nudge-clock-value"))) {
2423 sscanf (prop->value().c_str(), "%" PRId64, &f);
2424 nudge_clock->set (f);
2426 nudge_clock->set_mode (AudioClock::Timecode);
2427 nudge_clock->set (_session->frame_rate() * 5, true);
2434 Editor::get_state ()
2436 XMLNode* node = new XMLNode ("Editor");
2439 id().print (buf, sizeof (buf));
2440 node->add_property ("id", buf);
2442 if (is_realized()) {
2443 Glib::RefPtr<Gdk::Window> win = get_window();
2445 int x, y, width, height;
2446 win->get_root_origin(x, y);
2447 win->get_size(width, height);
2449 XMLNode* geometry = new XMLNode ("geometry");
2451 snprintf(buf, sizeof(buf), "%d", width);
2452 geometry->add_property("x-size", string(buf));
2453 snprintf(buf, sizeof(buf), "%d", height);
2454 geometry->add_property("y-size", string(buf));
2455 snprintf(buf, sizeof(buf), "%d", x);
2456 geometry->add_property("x-pos", string(buf));
2457 snprintf(buf, sizeof(buf), "%d", y);
2458 geometry->add_property("y-pos", string(buf));
2459 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2460 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2461 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2462 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2463 geometry->add_property("edit-vertical-pane-pos", string(buf));
2465 node->add_child_nocopy (*geometry);
2468 maybe_add_mixer_strip_width (*node);
2470 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2472 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2473 node->add_property ("zoom", buf);
2474 node->add_property ("snap-to", enum_2_string (_snap_type));
2475 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2476 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2477 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2478 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2479 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2480 node->add_property ("edit-point", enum_2_string (_edit_point));
2481 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2482 node->add_property ("visible-track-count", buf);
2484 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2485 node->add_property ("playhead", buf);
2486 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2487 node->add_property ("left-frame", buf);
2488 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2489 node->add_property ("y-origin", buf);
2491 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2492 node->add_property ("maximised", _maximised ? "yes" : "no");
2493 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2494 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2495 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2496 node->add_property ("mouse-mode", enum2str(mouse_mode));
2497 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2499 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2501 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2502 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2505 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2507 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2508 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2511 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2512 node->add_property (X_("editor-list-page"), buf);
2514 if (button_bindings) {
2515 XMLNode* bb = new XMLNode (X_("Buttons"));
2516 button_bindings->save (*bb);
2517 node->add_child_nocopy (*bb);
2520 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2522 node->add_child_nocopy (selection->get_state ());
2523 node->add_child_nocopy (_regions->get_state ());
2525 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2526 node->add_property ("nudge-clock-value", buf);
2531 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2532 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2534 * @return pair: TimeAxisView that y is over, layer index.
2536 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2537 * in stacked or expanded region display mode, otherwise 0.
2539 std::pair<TimeAxisView *, double>
2540 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2542 if (!trackview_relative_offset) {
2543 y -= _trackview_group->canvas_origin().y;
2547 return std::make_pair ( (TimeAxisView *) 0, 0);
2550 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2552 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2559 return std::make_pair ( (TimeAxisView *) 0, 0);
2562 /** Snap a position to the grid, if appropriate, taking into account current
2563 * grid settings and also the state of any snap modifier keys that may be pressed.
2564 * @param start Position to snap.
2565 * @param event Event to get current key modifier information from, or 0.
2568 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2570 if (!_session || !event) {
2574 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2575 if (_snap_mode == SnapOff) {
2576 snap_to_internal (start, direction, for_mark);
2579 if (_snap_mode != SnapOff) {
2580 snap_to_internal (start, direction, for_mark);
2586 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2588 if (!_session || _snap_mode == SnapOff) {
2592 snap_to_internal (start, direction, for_mark);
2596 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2598 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2599 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2601 switch (_snap_type) {
2602 case SnapToTimecodeFrame:
2603 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2604 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2605 /* start is already on a whole timecode frame, do nothing */
2606 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2607 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2609 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2613 case SnapToTimecodeSeconds:
2614 if (_session->config.get_timecode_offset_negative()) {
2615 start += _session->config.get_timecode_offset ();
2617 start -= _session->config.get_timecode_offset ();
2619 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2620 (start % one_timecode_second == 0)) {
2621 /* start is already on a whole second, do nothing */
2622 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2623 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2625 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2628 if (_session->config.get_timecode_offset_negative()) {
2629 start -= _session->config.get_timecode_offset ();
2631 start += _session->config.get_timecode_offset ();
2635 case SnapToTimecodeMinutes:
2636 if (_session->config.get_timecode_offset_negative()) {
2637 start += _session->config.get_timecode_offset ();
2639 start -= _session->config.get_timecode_offset ();
2641 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2642 (start % one_timecode_minute == 0)) {
2643 /* start is already on a whole minute, do nothing */
2644 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2645 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2647 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2649 if (_session->config.get_timecode_offset_negative()) {
2650 start -= _session->config.get_timecode_offset ();
2652 start += _session->config.get_timecode_offset ();
2656 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2657 abort(); /*NOTREACHED*/
2662 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2664 const framepos_t one_second = _session->frame_rate();
2665 const framepos_t one_minute = _session->frame_rate() * 60;
2666 framepos_t presnap = start;
2670 switch (_snap_type) {
2671 case SnapToTimecodeFrame:
2672 case SnapToTimecodeSeconds:
2673 case SnapToTimecodeMinutes:
2674 return timecode_snap_to_internal (start, direction, for_mark);
2677 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2678 start % (one_second/75) == 0) {
2679 /* start is already on a whole CD frame, do nothing */
2680 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2681 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2683 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2688 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2689 start % one_second == 0) {
2690 /* start is already on a whole second, do nothing */
2691 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2694 start = (framepos_t) floor ((double) start / one_second) * one_second;
2699 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2700 start % one_minute == 0) {
2701 /* start is already on a whole minute, do nothing */
2702 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2703 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2705 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2710 start = _session->tempo_map().round_to_bar (start, direction);
2714 start = _session->tempo_map().round_to_beat (start, direction);
2717 case SnapToBeatDiv128:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2720 case SnapToBeatDiv64:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2723 case SnapToBeatDiv32:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2726 case SnapToBeatDiv28:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2729 case SnapToBeatDiv24:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2732 case SnapToBeatDiv20:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2735 case SnapToBeatDiv16:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2738 case SnapToBeatDiv14:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2741 case SnapToBeatDiv12:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2744 case SnapToBeatDiv10:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2747 case SnapToBeatDiv8:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2750 case SnapToBeatDiv7:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2753 case SnapToBeatDiv6:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2756 case SnapToBeatDiv5:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2759 case SnapToBeatDiv4:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2762 case SnapToBeatDiv3:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2765 case SnapToBeatDiv2:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2774 _session->locations()->marks_either_side (start, before, after);
2776 if (before == max_framepos && after == max_framepos) {
2777 /* No marks to snap to, so just don't snap */
2779 } else if (before == max_framepos) {
2781 } else if (after == max_framepos) {
2783 } else if (before != max_framepos && after != max_framepos) {
2784 /* have before and after */
2785 if ((start - before) < (after - start)) {
2794 case SnapToRegionStart:
2795 case SnapToRegionEnd:
2796 case SnapToRegionSync:
2797 case SnapToRegionBoundary:
2798 if (!region_boundary_cache.empty()) {
2800 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2801 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2803 if (direction > 0) {
2804 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2806 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2809 if (next != region_boundary_cache.begin ()) {
2814 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2815 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2817 if (start > (p + n) / 2) {
2826 switch (_snap_mode) {
2832 if (presnap > start) {
2833 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2837 } else if (presnap < start) {
2838 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2844 /* handled at entry */
2852 Editor::setup_toolbar ()
2854 HBox* mode_box = manage(new HBox);
2855 mode_box->set_border_width (2);
2856 mode_box->set_spacing(2);
2858 HBox* mouse_mode_box = manage (new HBox);
2859 HBox* mouse_mode_hbox = manage (new HBox);
2860 VBox* mouse_mode_vbox = manage (new VBox);
2861 Alignment* mouse_mode_align = manage (new Alignment);
2863 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2864 mouse_mode_size_group->add_widget (smart_mode_button);
2865 mouse_mode_size_group->add_widget (mouse_move_button);
2866 mouse_mode_size_group->add_widget (mouse_cut_button);
2867 mouse_mode_size_group->add_widget (mouse_select_button);
2868 mouse_mode_size_group->add_widget (mouse_timefx_button);
2869 mouse_mode_size_group->add_widget (mouse_audition_button);
2870 mouse_mode_size_group->add_widget (mouse_draw_button);
2871 mouse_mode_size_group->add_widget (mouse_content_button);
2873 mouse_mode_size_group->add_widget (zoom_in_button);
2874 mouse_mode_size_group->add_widget (zoom_out_button);
2875 mouse_mode_size_group->add_widget (zoom_preset_selector);
2876 mouse_mode_size_group->add_widget (zoom_out_full_button);
2877 mouse_mode_size_group->add_widget (zoom_focus_selector);
2879 mouse_mode_size_group->add_widget (tav_shrink_button);
2880 mouse_mode_size_group->add_widget (tav_expand_button);
2881 mouse_mode_size_group->add_widget (visible_tracks_selector);
2883 mouse_mode_size_group->add_widget (snap_type_selector);
2884 mouse_mode_size_group->add_widget (snap_mode_selector);
2886 mouse_mode_size_group->add_widget (edit_point_selector);
2887 mouse_mode_size_group->add_widget (edit_mode_selector);
2889 mouse_mode_size_group->add_widget (*nudge_clock);
2890 mouse_mode_size_group->add_widget (nudge_forward_button);
2891 mouse_mode_size_group->add_widget (nudge_backward_button);
2893 mouse_mode_hbox->set_spacing (2);
2895 if (!ARDOUR::Profile->get_trx()) {
2896 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2899 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2900 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2902 if (!ARDOUR::Profile->get_mixbus()) {
2903 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2906 if (!ARDOUR::Profile->get_trx()) {
2907 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2908 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2909 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2910 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2913 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2915 mouse_mode_align->add (*mouse_mode_vbox);
2916 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2918 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2920 edit_mode_selector.set_name ("mouse mode button");
2922 if (!ARDOUR::Profile->get_trx()) {
2923 mode_box->pack_start (edit_mode_selector, false, false);
2925 mode_box->pack_start (*mouse_mode_box, false, false);
2927 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2928 _mouse_mode_tearoff->set_name ("MouseModeBase");
2929 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2931 if (Profile->get_sae() || Profile->get_mixbus() ) {
2932 _mouse_mode_tearoff->set_can_be_torn_off (false);
2935 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2936 &_mouse_mode_tearoff->tearoff_window()));
2937 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2938 &_mouse_mode_tearoff->tearoff_window(), 1));
2939 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2940 &_mouse_mode_tearoff->tearoff_window()));
2941 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2942 &_mouse_mode_tearoff->tearoff_window(), 1));
2946 _zoom_box.set_spacing (2);
2947 _zoom_box.set_border_width (2);
2951 zoom_preset_selector.set_name ("zoom button");
2952 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2953 zoom_preset_selector.set_size_request (42, -1);
2955 zoom_in_button.set_name ("zoom button");
2956 zoom_in_button.set_image(::get_icon ("zoom_in"));
2957 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2958 zoom_in_button.set_related_action (act);
2960 zoom_out_button.set_name ("zoom button");
2961 zoom_out_button.set_image(::get_icon ("zoom_out"));
2962 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2963 zoom_out_button.set_related_action (act);
2965 zoom_out_full_button.set_name ("zoom button");
2966 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2967 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2968 zoom_out_full_button.set_related_action (act);
2970 zoom_focus_selector.set_name ("zoom button");
2972 if (ARDOUR::Profile->get_mixbus()) {
2973 _zoom_box.pack_start (zoom_preset_selector, false, false);
2974 } else if (ARDOUR::Profile->get_trx()) {
2975 mode_box->pack_start (zoom_out_button, false, false);
2976 mode_box->pack_start (zoom_in_button, false, false);
2978 _zoom_box.pack_start (zoom_out_button, false, false);
2979 _zoom_box.pack_start (zoom_in_button, false, false);
2980 _zoom_box.pack_start (zoom_out_full_button, false, false);
2981 _zoom_box.pack_start (zoom_focus_selector, false, false);
2984 /* Track zoom buttons */
2985 visible_tracks_selector.set_name ("zoom button");
2986 if (Profile->get_mixbus()) {
2987 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2988 visible_tracks_selector.set_size_request (42, -1);
2990 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2993 tav_expand_button.set_name ("zoom button");
2994 tav_expand_button.set_image(::get_icon ("tav_exp"));
2995 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2996 tav_expand_button.set_related_action (act);
2998 tav_shrink_button.set_name ("zoom button");
2999 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
3000 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3001 tav_shrink_button.set_related_action (act);
3003 if (ARDOUR::Profile->get_mixbus()) {
3004 _zoom_box.pack_start (visible_tracks_selector);
3005 } else if (ARDOUR::Profile->get_trx()) {
3006 _zoom_box.pack_start (tav_shrink_button);
3007 _zoom_box.pack_start (tav_expand_button);
3009 _zoom_box.pack_start (visible_tracks_selector);
3010 _zoom_box.pack_start (tav_shrink_button);
3011 _zoom_box.pack_start (tav_expand_button);
3014 if (!ARDOUR::Profile->get_trx()) {
3015 _zoom_tearoff = manage (new TearOff (_zoom_box));
3017 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3018 &_zoom_tearoff->tearoff_window()));
3019 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3020 &_zoom_tearoff->tearoff_window(), 0));
3021 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3022 &_zoom_tearoff->tearoff_window()));
3023 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3024 &_zoom_tearoff->tearoff_window(), 0));
3027 if (Profile->get_sae() || Profile->get_mixbus() ) {
3028 _zoom_tearoff->set_can_be_torn_off (false);
3031 snap_box.set_spacing (2);
3032 snap_box.set_border_width (2);
3034 snap_type_selector.set_name ("mouse mode button");
3036 snap_mode_selector.set_name ("mouse mode button");
3038 edit_point_selector.set_name ("mouse mode button");
3040 snap_box.pack_start (snap_mode_selector, false, false);
3041 snap_box.pack_start (snap_type_selector, false, false);
3042 snap_box.pack_start (edit_point_selector, false, false);
3046 HBox *nudge_box = manage (new HBox);
3047 nudge_box->set_spacing (2);
3048 nudge_box->set_border_width (2);
3050 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3051 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3053 nudge_box->pack_start (nudge_backward_button, false, false);
3054 nudge_box->pack_start (nudge_forward_button, false, false);
3055 nudge_box->pack_start (*nudge_clock, false, false);
3058 /* Pack everything in... */
3060 HBox* hbox = manage (new HBox);
3061 hbox->set_spacing(2);
3063 _tools_tearoff = manage (new TearOff (*hbox));
3064 _tools_tearoff->set_name ("MouseModeBase");
3065 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3067 if (Profile->get_sae() || Profile->get_mixbus()) {
3068 _tools_tearoff->set_can_be_torn_off (false);
3071 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3072 &_tools_tearoff->tearoff_window()));
3073 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3074 &_tools_tearoff->tearoff_window(), 0));
3075 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3076 &_tools_tearoff->tearoff_window()));
3077 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3078 &_tools_tearoff->tearoff_window(), 0));
3080 toolbar_hbox.set_spacing (2);
3081 toolbar_hbox.set_border_width (1);
3083 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3084 if (!ARDOUR::Profile->get_trx()) {
3085 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3086 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3089 if (!ARDOUR::Profile->get_trx()) {
3090 hbox->pack_start (snap_box, false, false);
3091 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3092 hbox->pack_start (*nudge_box, false, false);
3094 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3097 hbox->pack_start (panic_box, false, false);
3101 toolbar_base.set_name ("ToolBarBase");
3102 toolbar_base.add (toolbar_hbox);
3104 _toolbar_viewport.add (toolbar_base);
3105 /* stick to the required height but allow width to vary if there's not enough room */
3106 _toolbar_viewport.set_size_request (1, -1);
3108 toolbar_frame.set_shadow_type (SHADOW_OUT);
3109 toolbar_frame.set_name ("BaseFrame");
3110 toolbar_frame.add (_toolbar_viewport);
3114 Editor::build_edit_point_menu ()
3116 using namespace Menu_Helpers;
3118 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3119 if(!Profile->get_mixbus())
3120 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3121 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3123 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3127 Editor::build_edit_mode_menu ()
3129 using namespace Menu_Helpers;
3131 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3132 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3133 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3134 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3136 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3140 Editor::build_snap_mode_menu ()
3142 using namespace Menu_Helpers;
3144 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3145 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3146 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3148 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3152 Editor::build_snap_type_menu ()
3154 using namespace Menu_Helpers;
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3181 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3182 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3187 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3192 Editor::setup_tooltips ()
3194 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3195 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3196 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3197 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3198 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3199 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3200 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3201 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3202 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3203 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3204 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3205 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3206 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3207 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3208 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3209 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3210 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3211 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3212 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3213 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3214 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3215 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3216 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3217 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3221 Editor::convert_drop_to_paths (
3222 vector<string>& paths,
3223 const RefPtr<Gdk::DragContext>& /*context*/,
3226 const SelectionData& data,
3230 if (_session == 0) {
3234 vector<string> uris = data.get_uris();
3238 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3239 are actually URI lists. So do it by hand.
3242 if (data.get_target() != "text/plain") {
3246 /* Parse the "uri-list" format that Nautilus provides,
3247 where each pathname is delimited by \r\n.
3249 THERE MAY BE NO NULL TERMINATING CHAR!!!
3252 string txt = data.get_text();
3256 p = (char *) malloc (txt.length() + 1);
3257 txt.copy (p, txt.length(), 0);
3258 p[txt.length()] = '\0';
3264 while (g_ascii_isspace (*p))
3268 while (*q && (*q != '\n') && (*q != '\r')) {
3275 while (q > p && g_ascii_isspace (*q))
3280 uris.push_back (string (p, q - p + 1));
3284 p = strchr (p, '\n');
3296 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3297 if ((*i).substr (0,7) == "file://") {
3298 paths.push_back (Glib::filename_from_uri (*i));
3306 Editor::new_tempo_section ()
3311 Editor::map_transport_state ()
3313 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3315 if (_session && _session->transport_stopped()) {
3316 have_pending_keyboard_selection = false;
3319 update_loop_range_view ();
3325 Editor::begin_selection_op_history ()
3327 selection_op_cmd_depth = 0;
3328 selection_op_history_it = 0;
3329 selection_op_history.clear();
3330 selection_undo_action->set_sensitive (false);
3331 selection_redo_action->set_sensitive (false);
3332 selection_op_history.push_front (&_selection_memento->get_state ());
3336 Editor::begin_reversible_selection_op (string name)
3339 //cerr << name << endl;
3340 /* begin/commit pairs can be nested */
3341 selection_op_cmd_depth++;
3346 Editor::commit_reversible_selection_op ()
3349 if (selection_op_cmd_depth == 1) {
3351 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3352 list<XMLNode *>::iterator it = selection_op_history.begin();
3353 advance (it, selection_op_history_it);
3354 selection_op_history.erase (selection_op_history.begin(), it);
3356 selection_op_history.push_front (&_selection_memento->get_state ());
3357 selection_op_history_it = 0;
3360 if (selection_op_cmd_depth > 0) {
3361 selection_op_cmd_depth--;
3364 selection_undo_action->set_sensitive (true);
3365 selection_redo_action->set_sensitive (false);
3370 Editor::undo_selection_op ()
3373 selection_op_history_it++;
3375 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3376 if (n == selection_op_history_it) {
3377 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3378 selection_redo_action->set_sensitive (true);
3383 /* is there an earlier entry? */
3384 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3385 selection_undo_action->set_sensitive (false);
3391 Editor::redo_selection_op ()
3394 if (selection_op_history_it > 0) {
3395 selection_op_history_it--;
3398 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3399 if (n == selection_op_history_it) {
3400 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3401 selection_undo_action->set_sensitive (true);
3407 if (selection_op_history_it == 0) {
3408 selection_redo_action->set_sensitive (false);
3414 Editor::begin_reversible_command (string name)
3417 before.push_back (&_selection_memento->get_state ());
3418 _session->begin_reversible_command (name);
3423 Editor::begin_reversible_command (GQuark q)
3426 before.push_back (&_selection_memento->get_state ());
3427 _session->begin_reversible_command (q);
3432 Editor::commit_reversible_command ()
3435 if (before.size() == 1) {
3436 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3437 undo_action->set_sensitive(true);
3438 begin_selection_op_history ();
3441 if (before.empty()) {
3442 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3447 _session->commit_reversible_command ();
3452 Editor::history_changed ()
3456 if (undo_action && _session) {
3457 if (_session->undo_depth() == 0) {
3458 label = S_("Command|Undo");
3460 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3462 undo_action->property_label() = label;
3465 if (redo_action && _session) {
3466 if (_session->redo_depth() == 0) {
3469 label = string_compose(_("Redo (%1)"), _session->next_redo());
3471 redo_action->property_label() = label;
3476 Editor::duplicate_range (bool with_dialog)
3480 RegionSelection rs = get_regions_from_selection_and_entered ();
3482 if ( selection->time.length() == 0 && rs.empty()) {
3488 ArdourDialog win (_("Duplicate"));
3489 Label label (_("Number of duplications:"));
3490 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3491 SpinButton spinner (adjustment, 0.0, 1);
3494 win.get_vbox()->set_spacing (12);
3495 win.get_vbox()->pack_start (hbox);
3496 hbox.set_border_width (6);
3497 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3499 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3500 place, visually. so do this by hand.
3503 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3504 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3505 spinner.grab_focus();
3511 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3512 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3513 win.set_default_response (RESPONSE_ACCEPT);
3515 spinner.grab_focus ();
3517 switch (win.run ()) {
3518 case RESPONSE_ACCEPT:
3524 times = adjustment.get_value();
3527 if ((current_mouse_mode() == Editing::MouseRange)) {
3528 if (selection->time.length()) {
3529 duplicate_selection (times);
3531 } else if (get_smart_mode()) {
3532 if (selection->time.length()) {
3533 duplicate_selection (times);
3535 duplicate_some_regions (rs, times);
3537 duplicate_some_regions (rs, times);
3542 Editor::set_edit_mode (EditMode m)
3544 Config->set_edit_mode (m);
3548 Editor::cycle_edit_mode ()
3550 switch (Config->get_edit_mode()) {
3552 if (Profile->get_sae()) {
3553 Config->set_edit_mode (Lock);
3555 Config->set_edit_mode (Ripple);
3560 Config->set_edit_mode (Lock);
3563 Config->set_edit_mode (Slide);
3569 Editor::edit_mode_selection_done ( EditMode m )
3571 Config->set_edit_mode ( m );
3575 Editor::snap_type_selection_done (SnapType snaptype)
3577 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3579 ract->set_active ();
3584 Editor::snap_mode_selection_done (SnapMode mode)
3586 RefPtr<RadioAction> ract = snap_mode_action (mode);
3589 ract->set_active (true);
3594 Editor::cycle_edit_point (bool with_marker)
3596 if(Profile->get_mixbus())
3597 with_marker = false;
3599 switch (_edit_point) {
3601 set_edit_point_preference (EditAtPlayhead);
3603 case EditAtPlayhead:
3605 set_edit_point_preference (EditAtSelectedMarker);
3607 set_edit_point_preference (EditAtMouse);
3610 case EditAtSelectedMarker:
3611 set_edit_point_preference (EditAtMouse);
3617 Editor::edit_point_selection_done (EditPoint ep)
3619 set_edit_point_preference ( ep );
3623 Editor::build_zoom_focus_menu ()
3625 using namespace Menu_Helpers;
3627 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3628 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3629 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3630 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3631 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3632 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3634 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3638 Editor::zoom_focus_selection_done ( ZoomFocus f )
3640 RefPtr<RadioAction> ract = zoom_focus_action (f);
3642 ract->set_active ();
3647 Editor::build_track_count_menu ()
3649 using namespace Menu_Helpers;
3651 if (!Profile->get_mixbus()) {
3652 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3653 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3654 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3655 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3656 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3657 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3658 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3659 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3660 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3661 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3662 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3663 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3668 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3669 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3670 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3671 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3672 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3673 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3674 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3675 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3677 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3678 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3679 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3680 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3681 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3682 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3683 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3684 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3685 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3686 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3687 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3692 Editor::set_zoom_preset (int64_t ms)
3695 temporal_zoom_session();
3699 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3700 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3704 Editor::set_visible_track_count (int32_t n)
3706 _visible_track_count = n;
3708 /* if the canvas hasn't really been allocated any size yet, just
3709 record the desired number of visible tracks and return. when canvas
3710 allocation happens, we will get called again and then we can do the
3714 if (_visible_canvas_height <= 1) {
3720 DisplaySuspender ds;
3722 if (_visible_track_count > 0) {
3723 h = trackviews_height() / _visible_track_count;
3724 std::ostringstream s;
3725 s << _visible_track_count;
3727 } else if (_visible_track_count == 0) {
3729 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3730 if ((*i)->marked_for_display()) {
3734 h = trackviews_height() / n;
3737 /* negative value means that the visible track count has
3738 been overridden by explicit track height changes.
3740 visible_tracks_selector.set_text (X_("*"));
3744 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3745 (*i)->set_height (h);
3748 if (str != visible_tracks_selector.get_text()) {
3749 visible_tracks_selector.set_text (str);
3754 Editor::override_visible_track_count ()
3756 _visible_track_count = -1;
3757 visible_tracks_selector.set_text ( _("*") );
3761 Editor::edit_controls_button_release (GdkEventButton* ev)
3763 if (Keyboard::is_context_menu_event (ev)) {
3764 ARDOUR_UI::instance()->add_route (this);
3765 } else if (ev->button == 1) {
3766 selection->clear_tracks ();
3773 Editor::mouse_select_button_release (GdkEventButton* ev)
3775 /* this handles just right-clicks */
3777 if (ev->button != 3) {
3785 Editor::set_zoom_focus (ZoomFocus f)
3787 string str = zoom_focus_strings[(int)f];
3789 if (str != zoom_focus_selector.get_text()) {
3790 zoom_focus_selector.set_text (str);
3793 if (zoom_focus != f) {
3800 Editor::cycle_zoom_focus ()
3802 switch (zoom_focus) {
3804 set_zoom_focus (ZoomFocusRight);
3806 case ZoomFocusRight:
3807 set_zoom_focus (ZoomFocusCenter);
3809 case ZoomFocusCenter:
3810 set_zoom_focus (ZoomFocusPlayhead);
3812 case ZoomFocusPlayhead:
3813 set_zoom_focus (ZoomFocusMouse);
3815 case ZoomFocusMouse:
3816 set_zoom_focus (ZoomFocusEdit);
3819 set_zoom_focus (ZoomFocusLeft);
3825 Editor::ensure_float (Window& win)
3827 win.set_transient_for (*this);
3831 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3833 /* recover or initialize pane positions. do this here rather than earlier because
3834 we don't want the positions to change the child allocations, which they seem to do.
3840 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3849 XMLNode* geometry = find_named_node (*node, "geometry");
3851 if (which == static_cast<Paned*> (&edit_pane)) {
3853 if (done & Horizontal) {
3857 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3858 _notebook_shrunk = string_is_affirmative (prop->value ());
3861 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3862 /* initial allocation is 90% to canvas, 10% to notebook */
3863 pos = (int) floor (alloc.get_width() * 0.90f);
3864 snprintf (buf, sizeof(buf), "%d", pos);
3866 pos = atoi (prop->value());
3869 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3870 edit_pane.set_position (pos);
3873 done = (Pane) (done | Horizontal);
3875 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3877 if (done & Vertical) {
3881 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3882 /* initial allocation is 90% to canvas, 10% to summary */
3883 pos = (int) floor (alloc.get_height() * 0.90f);
3884 snprintf (buf, sizeof(buf), "%d", pos);
3887 pos = atoi (prop->value());
3890 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3891 editor_summary_pane.set_position (pos);
3894 done = (Pane) (done | Vertical);
3899 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3901 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3902 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3903 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3904 top_hbox.remove (toolbar_frame);
3909 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3911 if (toolbar_frame.get_parent() == 0) {
3912 top_hbox.pack_end (toolbar_frame);
3917 Editor::set_show_measures (bool yn)
3919 if (_show_measures != yn) {
3922 if ((_show_measures = yn) == true) {
3924 tempo_lines->show();
3927 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3928 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3930 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3931 draw_measures (begin, end);
3939 Editor::toggle_follow_playhead ()
3941 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3943 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3944 set_follow_playhead (tact->get_active());
3948 /** @param yn true to follow playhead, otherwise false.
3949 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3952 Editor::set_follow_playhead (bool yn, bool catch_up)
3954 if (_follow_playhead != yn) {
3955 if ((_follow_playhead = yn) == true && catch_up) {
3957 reset_x_origin_to_follow_playhead ();
3964 Editor::toggle_stationary_playhead ()
3966 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3968 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3969 set_stationary_playhead (tact->get_active());
3974 Editor::set_stationary_playhead (bool yn)
3976 if (_stationary_playhead != yn) {
3977 if ((_stationary_playhead = yn) == true) {
3979 // FIXME need a 3.0 equivalent of this 2.X call
3980 // update_current_screen ();
3987 Editor::playlist_selector () const
3989 return *_playlist_selector;
3993 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3995 if (paste_count == 0) {
3996 /* don't bother calculating an offset that will be zero anyway */
4000 /* calculate basic unsnapped multi-paste offset */
4001 framecnt_t offset = paste_count * duration;
4003 /* snap offset so pos + offset is aligned to the grid */
4004 framepos_t offset_pos = pos + offset;
4005 snap_to(offset_pos, RoundUpMaybe);
4006 offset = offset_pos - pos;
4012 Editor::get_grid_beat_divisions(framepos_t position)
4014 switch (_snap_type) {
4015 case SnapToBeatDiv128: return 128;
4016 case SnapToBeatDiv64: return 64;
4017 case SnapToBeatDiv32: return 32;
4018 case SnapToBeatDiv28: return 28;
4019 case SnapToBeatDiv24: return 24;
4020 case SnapToBeatDiv20: return 20;
4021 case SnapToBeatDiv16: return 16;
4022 case SnapToBeatDiv14: return 14;
4023 case SnapToBeatDiv12: return 12;
4024 case SnapToBeatDiv10: return 10;
4025 case SnapToBeatDiv8: return 8;
4026 case SnapToBeatDiv7: return 7;
4027 case SnapToBeatDiv6: return 6;
4028 case SnapToBeatDiv5: return 5;
4029 case SnapToBeatDiv4: return 4;
4030 case SnapToBeatDiv3: return 3;
4031 case SnapToBeatDiv2: return 2;
4038 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4042 const unsigned divisions = get_grid_beat_divisions(position);
4044 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4047 switch (_snap_type) {
4049 return Evoral::Beats(1.0);
4052 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4060 return Evoral::Beats();
4064 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4068 ret = nudge_clock->current_duration (pos);
4069 next = ret + 1; /* XXXX fix me */
4075 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4077 ArdourDialog dialog (_("Playlist Deletion"));
4078 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4079 "If it is kept, its audio files will not be cleaned.\n"
4080 "If it is deleted, audio files used by it alone will be cleaned."),
4083 dialog.set_position (WIN_POS_CENTER);
4084 dialog.get_vbox()->pack_start (label);
4088 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4089 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4090 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4092 switch (dialog.run ()) {
4093 case RESPONSE_ACCEPT:
4094 /* delete the playlist */
4098 case RESPONSE_REJECT:
4099 /* keep the playlist */
4111 Editor::audio_region_selection_covers (framepos_t where)
4113 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4114 if ((*a)->region()->covers (where)) {
4123 Editor::prepare_for_cleanup ()
4125 cut_buffer->clear_regions ();
4126 cut_buffer->clear_playlists ();
4128 selection->clear_regions ();
4129 selection->clear_playlists ();
4131 _regions->suspend_redisplay ();
4135 Editor::finish_cleanup ()
4137 _regions->resume_redisplay ();
4141 Editor::transport_loop_location()
4144 return _session->locations()->auto_loop_location();
4151 Editor::transport_punch_location()
4154 return _session->locations()->auto_punch_location();
4161 Editor::control_layout_scroll (GdkEventScroll* ev)
4163 /* Just forward to the normal canvas scroll method. The coordinate
4164 systems are different but since the canvas is always larger than the
4165 track headers, and aligned with the trackview area, this will work.
4167 In the not too distant future this layout is going away anyway and
4168 headers will be on the canvas.
4170 return canvas_scroll_event (ev, false);
4174 Editor::session_state_saved (string)
4177 _snapshots->redisplay ();
4181 Editor::update_tearoff_visibility()
4183 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4184 _mouse_mode_tearoff->set_visible (visible);
4185 _tools_tearoff->set_visible (visible);
4186 if (_zoom_tearoff) {
4187 _zoom_tearoff->set_visible (visible);
4192 Editor::reattach_all_tearoffs ()
4194 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4195 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4196 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4200 Editor::maximise_editing_space ()
4212 Editor::restore_editing_space ()
4224 * Make new playlists for a given track and also any others that belong
4225 * to the same active route group with the `select' property.
4230 Editor::new_playlists (TimeAxisView* v)
4232 begin_reversible_command (_("new playlists"));
4233 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4234 _session->playlists->get (playlists);
4235 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4236 commit_reversible_command ();
4240 * Use a copy of the current playlist for a given track and also any others that belong
4241 * to the same active route group with the `select' property.
4246 Editor::copy_playlists (TimeAxisView* v)
4248 begin_reversible_command (_("copy playlists"));
4249 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4250 _session->playlists->get (playlists);
4251 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4252 commit_reversible_command ();
4255 /** Clear the current playlist for a given track and also any others that belong
4256 * to the same active route group with the `select' property.
4261 Editor::clear_playlists (TimeAxisView* v)
4263 begin_reversible_command (_("clear playlists"));
4264 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4265 _session->playlists->get (playlists);
4266 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4267 commit_reversible_command ();
4271 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4273 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4277 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4279 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4283 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4285 atv.clear_playlist ();
4289 Editor::on_key_press_event (GdkEventKey* ev)
4291 return key_press_focus_accelerator_handler (*this, ev);
4295 Editor::on_key_release_event (GdkEventKey* ev)
4297 return Gtk::Window::on_key_release_event (ev);
4298 // return key_press_focus_accelerator_handler (*this, ev);
4302 Editor::get_y_origin () const
4304 return vertical_adjustment.get_value ();
4307 /** Queue up a change to the viewport x origin.
4308 * @param frame New x origin.
4311 Editor::reset_x_origin (framepos_t frame)
4313 pending_visual_change.add (VisualChange::TimeOrigin);
4314 pending_visual_change.time_origin = frame;
4315 ensure_visual_change_idle_handler ();
4319 Editor::reset_y_origin (double y)
4321 pending_visual_change.add (VisualChange::YOrigin);
4322 pending_visual_change.y_origin = y;
4323 ensure_visual_change_idle_handler ();
4327 Editor::reset_zoom (framecnt_t spp)
4329 if (spp == samples_per_pixel) {
4333 pending_visual_change.add (VisualChange::ZoomLevel);
4334 pending_visual_change.samples_per_pixel = spp;
4335 ensure_visual_change_idle_handler ();
4339 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4341 reset_x_origin (frame);
4344 if (!no_save_visual) {
4345 undo_visual_stack.push_back (current_visual_state(false));
4349 Editor::VisualState::VisualState (bool with_tracks)
4350 : gui_state (with_tracks ? new GUIObjectState : 0)
4354 Editor::VisualState::~VisualState ()
4359 Editor::VisualState*
4360 Editor::current_visual_state (bool with_tracks)
4362 VisualState* vs = new VisualState (with_tracks);
4363 vs->y_position = vertical_adjustment.get_value();
4364 vs->samples_per_pixel = samples_per_pixel;
4365 vs->leftmost_frame = leftmost_frame;
4366 vs->zoom_focus = zoom_focus;
4369 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4376 Editor::undo_visual_state ()
4378 if (undo_visual_stack.empty()) {
4382 VisualState* vs = undo_visual_stack.back();
4383 undo_visual_stack.pop_back();
4386 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4389 use_visual_state (*vs);
4394 Editor::redo_visual_state ()
4396 if (redo_visual_stack.empty()) {
4400 VisualState* vs = redo_visual_stack.back();
4401 redo_visual_stack.pop_back();
4403 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4404 // why do we check here?
4405 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4408 use_visual_state (*vs);
4413 Editor::swap_visual_state ()
4415 if (undo_visual_stack.empty()) {
4416 redo_visual_state ();
4418 undo_visual_state ();
4423 Editor::use_visual_state (VisualState& vs)
4425 PBD::Unwinder<bool> nsv (no_save_visual, true);
4426 DisplaySuspender ds;
4428 vertical_adjustment.set_value (vs.y_position);
4430 set_zoom_focus (vs.zoom_focus);
4431 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4434 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4436 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4437 (*i)->reset_visual_state ();
4441 _routes->update_visibility ();
4444 /** This is the core function that controls the zoom level of the canvas. It is called
4445 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4446 * @param spp new number of samples per pixel
4449 Editor::set_samples_per_pixel (framecnt_t spp)
4455 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4456 const framecnt_t lots_of_pixels = 4000;
4458 /* if the zoom level is greater than what you'd get trying to display 3
4459 * days of audio on a really big screen, then it's too big.
4462 if (spp * lots_of_pixels > three_days) {
4466 samples_per_pixel = spp;
4469 tempo_lines->tempo_map_changed();
4472 bool const showing_time_selection = selection->time.length() > 0;
4474 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4475 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4476 (*i)->reshow_selection (selection->time);
4480 ZoomChanged (); /* EMIT_SIGNAL */
4482 ArdourCanvas::GtkCanvasViewport* c;
4484 c = get_track_canvas();
4486 c->canvas()->zoomed ();
4489 if (playhead_cursor) {
4490 playhead_cursor->set_position (playhead_cursor->current_frame ());
4493 refresh_location_display();
4494 _summary->set_overlays_dirty ();
4496 update_marker_labels ();
4502 Editor::queue_visual_videotimeline_update ()
4505 * pending_visual_change.add (VisualChange::VideoTimeline);
4506 * or maybe even more specific: which videotimeline-image
4507 * currently it calls update_video_timeline() to update
4508 * _all outdated_ images on the video-timeline.
4509 * see 'exposeimg()' in video_image_frame.cc
4511 ensure_visual_change_idle_handler ();
4515 Editor::ensure_visual_change_idle_handler ()
4517 if (pending_visual_change.idle_handler_id < 0) {
4518 // see comment in add_to_idle_resize above.
4519 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4520 pending_visual_change.being_handled = false;
4525 Editor::_idle_visual_changer (void* arg)
4527 return static_cast<Editor*>(arg)->idle_visual_changer ();
4531 Editor::idle_visual_changer ()
4533 /* set_horizontal_position() below (and maybe other calls) call
4534 gtk_main_iteration(), so it's possible that a signal will be handled
4535 half-way through this method. If this signal wants an
4536 idle_visual_changer we must schedule another one after this one, so
4537 mark the idle_handler_id as -1 here to allow that. Also make a note
4538 that we are doing the visual change, so that changes in response to
4539 super-rapid-screen-update can be dropped if we are still processing
4543 pending_visual_change.idle_handler_id = -1;
4544 pending_visual_change.being_handled = true;
4546 VisualChange vc = pending_visual_change;
4548 pending_visual_change.pending = (VisualChange::Type) 0;
4550 visual_changer (vc);
4552 pending_visual_change.being_handled = false;
4554 return 0; /* this is always a one-shot call */
4558 Editor::visual_changer (const VisualChange& vc)
4560 double const last_time_origin = horizontal_position ();
4562 if (vc.pending & VisualChange::ZoomLevel) {
4563 set_samples_per_pixel (vc.samples_per_pixel);
4565 compute_fixed_ruler_scale ();
4567 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4568 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4570 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4571 current_bbt_points_begin, current_bbt_points_end);
4572 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4573 current_bbt_points_begin, current_bbt_points_end);
4574 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4576 update_video_timeline();
4579 if (vc.pending & VisualChange::TimeOrigin) {
4580 set_horizontal_position (vc.time_origin / samples_per_pixel);
4583 if (vc.pending & VisualChange::YOrigin) {
4584 vertical_adjustment.set_value (vc.y_origin);
4587 if (last_time_origin == horizontal_position ()) {
4588 /* changed signal not emitted */
4589 update_fixed_rulers ();
4590 redisplay_tempo (true);
4593 if (!(vc.pending & VisualChange::ZoomLevel)) {
4594 update_video_timeline();
4597 _summary->set_overlays_dirty ();
4600 struct EditorOrderTimeAxisSorter {
4601 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4602 return a->order () < b->order ();
4607 Editor::sort_track_selection (TrackViewList& sel)
4609 EditorOrderTimeAxisSorter cmp;
4614 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu, bool from_outside_canvas)
4617 framepos_t where = 0;
4618 EditPoint ep = _edit_point;
4620 if(Profile->get_mixbus())
4621 if (ep == EditAtSelectedMarker)
4624 if (from_outside_canvas && (ep == EditAtMouse)) {
4625 ep = EditAtPlayhead;
4626 } else if (from_context_menu && (ep == EditAtMouse)) {
4627 return canvas_event_sample (&context_click_event, 0, 0);
4630 if (entered_marker) {
4631 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4632 return entered_marker->position();
4635 if (ignore_playhead && ep == EditAtPlayhead) {
4636 ep = EditAtSelectedMarker;
4640 case EditAtPlayhead:
4641 where = _session->audible_frame();
4642 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4645 case EditAtSelectedMarker:
4646 if (!selection->markers.empty()) {
4648 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4651 where = loc->start();
4655 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4663 if (!mouse_frame (where, ignored)) {
4664 /* XXX not right but what can we do ? */
4668 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4676 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4678 if (!_session) return;
4680 begin_reversible_command (cmd);
4684 if ((tll = transport_loop_location()) == 0) {
4685 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4686 XMLNode &before = _session->locations()->get_state();
4687 _session->locations()->add (loc, true);
4688 _session->set_auto_loop_location (loc);
4689 XMLNode &after = _session->locations()->get_state();
4690 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4692 XMLNode &before = tll->get_state();
4693 tll->set_hidden (false, this);
4694 tll->set (start, end);
4695 XMLNode &after = tll->get_state();
4696 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4699 commit_reversible_command ();
4703 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4705 if (!_session) return;
4707 begin_reversible_command (cmd);
4711 if ((tpl = transport_punch_location()) == 0) {
4712 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4713 XMLNode &before = _session->locations()->get_state();
4714 _session->locations()->add (loc, true);
4715 _session->set_auto_punch_location (loc);
4716 XMLNode &after = _session->locations()->get_state();
4717 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4719 XMLNode &before = tpl->get_state();
4720 tpl->set_hidden (false, this);
4721 tpl->set (start, end);
4722 XMLNode &after = tpl->get_state();
4723 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4726 commit_reversible_command ();
4729 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4730 * @param rs List to which found regions are added.
4731 * @param where Time to look at.
4732 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4735 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4737 const TrackViewList* tracks;
4740 tracks = &track_views;
4745 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4747 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4750 boost::shared_ptr<Track> tr;
4751 boost::shared_ptr<Playlist> pl;
4753 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4755 boost::shared_ptr<RegionList> regions = pl->regions_at (
4756 (framepos_t) floor ( (double) where * tr->speed()));
4758 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4759 RegionView* rv = rtv->view()->find_view (*i);
4770 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4772 const TrackViewList* tracks;
4775 tracks = &track_views;
4780 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4781 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4783 boost::shared_ptr<Track> tr;
4784 boost::shared_ptr<Playlist> pl;
4786 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4788 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4789 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4791 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4793 RegionView* rv = rtv->view()->find_view (*i);
4804 /** Get regions using the following method:
4806 * Make a region list using:
4807 * (a) any selected regions
4808 * (b) the intersection of any selected tracks and the edit point(*)
4809 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4811 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4813 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4817 Editor::get_regions_from_selection_and_edit_point ()
4819 RegionSelection regions;
4821 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4822 regions.add (entered_regionview);
4824 regions = selection->regions;
4827 if ( regions.empty() ) {
4828 TrackViewList tracks = selection->tracks;
4830 if (!tracks.empty()) {
4831 /* no region selected or entered, but some selected tracks:
4832 * act on all regions on the selected tracks at the edit point
4834 framepos_t const where = get_preferred_edit_position ();
4835 get_regions_at(regions, where, tracks);
4842 /** Get regions using the following method:
4844 * Make a region list using:
4845 * (a) any selected regions
4846 * (b) the intersection of any selected tracks and the edit point(*)
4847 * (c) if neither exists, then whatever region is under the mouse
4849 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4851 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4854 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4856 RegionSelection regions;
4858 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4859 regions.add (entered_regionview);
4861 regions = selection->regions;
4864 if ( regions.empty() ) {
4865 TrackViewList tracks = selection->tracks;
4867 if (!tracks.empty()) {
4868 /* no region selected or entered, but some selected tracks:
4869 * act on all regions on the selected tracks at the edit point
4871 get_regions_at(regions, pos, tracks);
4878 /** Start with regions that are selected, or the entered regionview if none are selected.
4879 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4880 * of the regions that we started with.
4884 Editor::get_regions_from_selection_and_entered ()
4886 RegionSelection regions = selection->regions;
4888 if (regions.empty() && entered_regionview) {
4889 regions.add (entered_regionview);
4896 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4898 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4899 RouteTimeAxisView* tatv;
4901 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4902 boost::shared_ptr<Playlist> pl;
4903 std::vector<boost::shared_ptr<Region> > results;
4904 boost::shared_ptr<Track> tr;
4906 if ((tr = tatv->track()) == 0) {
4911 if ((pl = (tr->playlist())) != 0) {
4912 boost::shared_ptr<Region> r = pl->region_by_id (id);
4914 RegionView* marv = tatv->view()->find_view (r);
4916 regions.push_back (marv);
4925 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4927 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4929 RouteTimeAxisView* tatv;
4931 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4933 boost::shared_ptr<Playlist> pl;
4934 vector<boost::shared_ptr<Region> > results;
4936 boost::shared_ptr<Track> tr;
4938 if ((tr = tatv->track()) == 0) {
4943 if ((pl = (tr->playlist())) != 0) {
4944 if (src_comparison) {
4945 pl->get_source_equivalent_regions (region, results);
4947 pl->get_region_list_equivalent_regions (region, results);
4951 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4952 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4953 regions.push_back (marv);
4962 Editor::show_rhythm_ferret ()
4964 if (rhythm_ferret == 0) {
4965 rhythm_ferret = new RhythmFerret(*this);
4968 rhythm_ferret->set_session (_session);
4969 rhythm_ferret->show ();
4970 rhythm_ferret->present ();
4974 Editor::first_idle ()
4976 MessageDialog* dialog = 0;
4978 if (track_views.size() > 1) {
4979 dialog = new MessageDialog (
4981 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4985 ARDOUR_UI::instance()->flush_pending ();
4988 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4992 // first idle adds route children (automation tracks), so we need to redisplay here
4993 _routes->redisplay ();
4997 if (_session->undo_depth() == 0) {
4998 undo_action->set_sensitive(false);
5000 redo_action->set_sensitive(false);
5001 begin_selection_op_history ();
5007 Editor::_idle_resize (gpointer arg)
5009 return ((Editor*)arg)->idle_resize ();
5013 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5015 if (resize_idle_id < 0) {
5016 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5017 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5018 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5020 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5021 _pending_resize_amount = 0;
5024 /* make a note of the smallest resulting height, so that we can clamp the
5025 lower limit at TimeAxisView::hSmall */
5027 int32_t min_resulting = INT32_MAX;
5029 _pending_resize_amount += h;
5030 _pending_resize_view = view;
5032 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5034 if (selection->tracks.contains (_pending_resize_view)) {
5035 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5036 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5040 if (min_resulting < 0) {
5045 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5046 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5050 /** Handle pending resizing of tracks */
5052 Editor::idle_resize ()
5054 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5056 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5057 selection->tracks.contains (_pending_resize_view)) {
5059 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5060 if (*i != _pending_resize_view) {
5061 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5066 _pending_resize_amount = 0;
5067 _group_tabs->set_dirty ();
5068 resize_idle_id = -1;
5076 ENSURE_GUI_THREAD (*this, &Editor::located);
5079 playhead_cursor->set_position (_session->audible_frame ());
5080 if (_follow_playhead && !_pending_initial_locate) {
5081 reset_x_origin_to_follow_playhead ();
5085 _pending_locate_request = false;
5086 _pending_initial_locate = false;
5090 Editor::region_view_added (RegionView * rv)
5092 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5093 if (rv->region ()->id () == (*pr)) {
5094 selection->add (rv);
5095 selection->regions.pending.erase (pr);
5099 _summary->set_background_dirty ();
5103 Editor::region_view_removed ()
5105 _summary->set_background_dirty ();
5109 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5111 TrackViewList::const_iterator j = track_views.begin ();
5112 while (j != track_views.end()) {
5113 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5114 if (rtv && rtv->route() == r) {
5125 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5129 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5130 TimeAxisView* tv = axis_view_from_route (*i);
5140 Editor::suspend_route_redisplay ()
5143 _routes->suspend_redisplay();
5148 Editor::resume_route_redisplay ()
5151 _routes->resume_redisplay();
5156 Editor::add_routes (RouteList& routes)
5158 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5160 RouteTimeAxisView *rtv;
5161 list<RouteTimeAxisView*> new_views;
5163 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5164 boost::shared_ptr<Route> route = (*x);
5166 if (route->is_auditioner() || route->is_monitor()) {
5170 DataType dt = route->input()->default_type();
5172 if (dt == ARDOUR::DataType::AUDIO) {
5173 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5174 rtv->set_route (route);
5175 } else if (dt == ARDOUR::DataType::MIDI) {
5176 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5177 rtv->set_route (route);
5179 throw unknown_type();
5182 new_views.push_back (rtv);
5183 track_views.push_back (rtv);
5185 rtv->effective_gain_display ();
5187 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5188 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5191 if (new_views.size() > 0) {
5192 _routes->routes_added (new_views);
5193 _summary->routes_added (new_views);
5196 if (show_editor_mixer_when_tracks_arrive) {
5197 show_editor_mixer (true);
5200 editor_list_button.set_sensitive (true);
5204 Editor::timeaxisview_deleted (TimeAxisView *tv)
5206 if (tv == entered_track) {
5210 if (_session && _session->deletion_in_progress()) {
5211 /* the situation is under control */
5215 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5217 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5219 _routes->route_removed (tv);
5221 TimeAxisView::Children c = tv->get_child_list ();
5222 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5223 if (entered_track == i->get()) {
5228 /* remove it from the list of track views */
5230 TrackViewList::iterator i;
5232 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5233 i = track_views.erase (i);
5236 /* update whatever the current mixer strip is displaying, if revelant */
5238 boost::shared_ptr<Route> route;
5241 route = rtav->route ();
5244 if (current_mixer_strip && current_mixer_strip->route() == route) {
5246 TimeAxisView* next_tv;
5248 if (track_views.empty()) {
5250 } else if (i == track_views.end()) {
5251 next_tv = track_views.front();
5258 set_selected_mixer_strip (*next_tv);
5260 /* make the editor mixer strip go away setting the
5261 * button to inactive (which also unticks the menu option)
5264 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5270 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5272 if (apply_to_selection) {
5273 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5275 TrackSelection::iterator j = i;
5278 hide_track_in_display (*i, false);
5283 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5285 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5286 // this will hide the mixer strip
5287 set_selected_mixer_strip (*tv);
5290 _routes->hide_track_in_display (*tv);
5295 Editor::sync_track_view_list_and_routes ()
5297 track_views = TrackViewList (_routes->views ());
5299 _summary->set_dirty ();
5300 _group_tabs->set_dirty ();
5302 return false; // do not call again (until needed)
5306 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5308 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5313 /** Find a RouteTimeAxisView by the ID of its route */
5315 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5317 RouteTimeAxisView* v;
5319 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5320 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5321 if(v->route()->id() == id) {
5331 Editor::fit_route_group (RouteGroup *g)
5333 TrackViewList ts = axis_views_from_routes (g->route_list ());
5338 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5340 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5343 _session->cancel_audition ();
5347 if (_session->is_auditioning()) {
5348 _session->cancel_audition ();
5349 if (r == last_audition_region) {
5354 _session->audition_region (r);
5355 last_audition_region = r;
5360 Editor::hide_a_region (boost::shared_ptr<Region> r)
5362 r->set_hidden (true);
5366 Editor::show_a_region (boost::shared_ptr<Region> r)
5368 r->set_hidden (false);
5372 Editor::audition_region_from_region_list ()
5374 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5378 Editor::hide_region_from_region_list ()
5380 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5384 Editor::show_region_in_region_list ()
5386 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5390 Editor::step_edit_status_change (bool yn)
5393 start_step_editing ();
5395 stop_step_editing ();
5400 Editor::start_step_editing ()
5402 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5406 Editor::stop_step_editing ()
5408 step_edit_connection.disconnect ();
5412 Editor::check_step_edit ()
5414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5415 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5417 mtv->check_step_edit ();
5421 return true; // do it again, till we stop
5425 Editor::scroll_press (Direction dir)
5427 ++_scroll_callbacks;
5429 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5430 /* delay the first auto-repeat */
5436 scroll_backward (1);
5444 scroll_up_one_track ();
5448 scroll_down_one_track ();
5452 /* do hacky auto-repeat */
5453 if (!_scroll_connection.connected ()) {
5455 _scroll_connection = Glib::signal_timeout().connect (
5456 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5459 _scroll_callbacks = 0;
5466 Editor::scroll_release ()
5468 _scroll_connection.disconnect ();
5471 /** Queue a change for the Editor viewport x origin to follow the playhead */
5473 Editor::reset_x_origin_to_follow_playhead ()
5475 framepos_t const frame = playhead_cursor->current_frame ();
5477 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5479 if (_session->transport_speed() < 0) {
5481 if (frame > (current_page_samples() / 2)) {
5482 center_screen (frame-(current_page_samples()/2));
5484 center_screen (current_page_samples()/2);
5491 if (frame < leftmost_frame) {
5493 if (_session->transport_rolling()) {
5494 /* rolling; end up with the playhead at the right of the page */
5495 l = frame - current_page_samples ();
5497 /* not rolling: end up with the playhead 1/4 of the way along the page */
5498 l = frame - current_page_samples() / 4;
5502 if (_session->transport_rolling()) {
5503 /* rolling: end up with the playhead on the left of the page */
5506 /* not rolling: end up with the playhead 3/4 of the way along the page */
5507 l = frame - 3 * current_page_samples() / 4;
5515 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5521 Editor::super_rapid_screen_update ()
5523 if (!_session || !_session->engine().running()) {
5527 /* METERING / MIXER STRIPS */
5529 /* update track meters, if required */
5530 if (is_mapped() && meters_running) {
5531 RouteTimeAxisView* rtv;
5532 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5533 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5534 rtv->fast_update ();
5539 /* and any current mixer strip */
5540 if (current_mixer_strip) {
5541 current_mixer_strip->fast_update ();
5544 /* PLAYHEAD AND VIEWPORT */
5546 framepos_t const frame = _session->audible_frame();
5548 /* There are a few reasons why we might not update the playhead / viewport stuff:
5550 * 1. we don't update things when there's a pending locate request, otherwise
5551 * when the editor requests a locate there is a chance that this method
5552 * will move the playhead before the locate request is processed, causing
5554 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5555 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5558 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5560 last_update_frame = frame;
5562 if (!_dragging_playhead) {
5563 playhead_cursor->set_position (frame);
5566 if (!_stationary_playhead) {
5568 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5569 /* We only do this if we aren't already
5570 handling a visual change (ie if
5571 pending_visual_change.being_handled is
5572 false) so that these requests don't stack
5573 up there are too many of them to handle in
5576 reset_x_origin_to_follow_playhead ();
5581 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5585 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5586 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5587 if (target <= 0.0) {
5590 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5591 target = (target * 0.15) + (current * 0.85);
5597 set_horizontal_position (current);
5606 Editor::session_going_away ()
5608 _have_idled = false;
5610 _session_connections.drop_connections ();
5612 super_rapid_screen_update_connection.disconnect ();
5614 selection->clear ();
5615 cut_buffer->clear ();
5617 clicked_regionview = 0;
5618 clicked_axisview = 0;
5619 clicked_routeview = 0;
5620 entered_regionview = 0;
5622 last_update_frame = 0;
5625 playhead_cursor->hide ();
5627 /* rip everything out of the list displays */
5631 _route_groups->clear ();
5633 /* do this first so that deleting a track doesn't reset cms to null
5634 and thus cause a leak.
5637 if (current_mixer_strip) {
5638 if (current_mixer_strip->get_parent() != 0) {
5639 global_hpacker.remove (*current_mixer_strip);
5641 delete current_mixer_strip;
5642 current_mixer_strip = 0;
5645 /* delete all trackviews */
5647 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5650 track_views.clear ();
5652 nudge_clock->set_session (0);
5654 editor_list_button.set_active(false);
5655 editor_list_button.set_sensitive(false);
5657 /* clear tempo/meter rulers */
5658 remove_metric_marks ();
5660 clear_marker_display ();
5662 stop_step_editing ();
5664 /* get rid of any existing editor mixer strip */
5666 WindowTitle title(Glib::get_application_name());
5667 title += _("Editor");
5669 set_title (title.get_string());
5671 SessionHandlePtr::session_going_away ();
5676 Editor::show_editor_list (bool yn)
5679 _the_notebook.show ();
5681 _the_notebook.hide ();
5686 Editor::change_region_layering_order (bool from_context_menu)
5688 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5690 if (!clicked_routeview) {
5691 if (layering_order_editor) {
5692 layering_order_editor->hide ();
5697 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5703 boost::shared_ptr<Playlist> pl = track->playlist();
5709 if (layering_order_editor == 0) {
5710 layering_order_editor = new RegionLayeringOrderEditor (*this);
5713 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5714 layering_order_editor->maybe_present ();
5718 Editor::update_region_layering_order_editor ()
5720 if (layering_order_editor && layering_order_editor->is_visible ()) {
5721 change_region_layering_order (true);
5726 Editor::setup_fade_images ()
5728 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5729 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5730 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5731 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5732 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5734 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5735 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5736 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5737 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5738 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5740 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5741 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5742 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5743 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5744 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5746 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5747 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5748 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5749 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5750 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5754 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5756 Editor::action_menu_item (std::string const & name)
5758 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5761 return *manage (a->create_menu_item ());
5765 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5767 EventBox* b = manage (new EventBox);
5768 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5769 Label* l = manage (new Label (name));
5773 _the_notebook.append_page (widget, *b);
5777 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5779 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5780 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5783 if (ev->type == GDK_2BUTTON_PRESS) {
5785 /* double-click on a notebook tab shrinks or expands the notebook */
5787 if (_notebook_shrunk) {
5788 if (pre_notebook_shrink_pane_width) {
5789 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5791 _notebook_shrunk = false;
5793 pre_notebook_shrink_pane_width = edit_pane.get_position();
5795 /* this expands the LHS of the edit pane to cover the notebook
5796 PAGE but leaves the tabs visible.
5798 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5799 _notebook_shrunk = true;
5807 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5809 using namespace Menu_Helpers;
5811 MenuList& items = _control_point_context_menu.items ();
5814 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5815 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5816 if (!can_remove_control_point (item)) {
5817 items.back().set_sensitive (false);
5820 _control_point_context_menu.popup (event->button.button, event->button.time);
5824 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5826 using namespace Menu_Helpers;
5828 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5833 /* We need to get the selection here and pass it to the operations, since
5834 popping up the menu will cause a region leave event which clears
5835 entered_regionview. */
5837 MidiRegionView& mrv = note->region_view();
5838 const RegionSelection rs = get_regions_from_selection_and_entered ();
5840 MenuList& items = _note_context_menu.items();
5843 items.push_back(MenuElem(_("Delete"),
5844 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5845 items.push_back(MenuElem(_("Edit..."),
5846 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5847 items.push_back(MenuElem(_("Legatize"),
5848 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5849 items.push_back(MenuElem(_("Quantize..."),
5850 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5851 items.push_back(MenuElem(_("Remove Overlap"),
5852 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5853 items.push_back(MenuElem(_("Transform..."),
5854 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5856 _note_context_menu.popup (event->button.button, event->button.time);
5860 Editor::zoom_vertical_modifier_released()
5862 _stepping_axis_view = 0;
5866 Editor::ui_parameter_changed (string parameter)
5868 if (parameter == "icon-set") {
5869 while (!_cursor_stack.empty()) {
5870 _cursor_stack.pop_back();
5872 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5873 _cursor_stack.push_back(_cursors->grabber);
5874 } else if (parameter == "draggable-playhead") {
5875 if (_verbose_cursor) {
5876 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());