2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <glibmm/uriutils.h>
51 #include <gtkmm/image.h>
52 #include <gdkmm/color.h>
53 #include <gdkmm/bitmap.h>
55 #include <gtkmm/menu.h>
56 #include <gtkmm/menuitem.h>
58 #include "gtkmm2ext/bindings.h"
59 #include "gtkmm2ext/grouped_buttons.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/tearoff.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/location.h"
71 #include "ardour/profile.h"
72 #include "ardour/route_group.h"
73 #include "ardour/session_playlists.h"
74 #include "ardour/tempo.h"
75 #include "ardour/utils.h"
77 #include "canvas/debug.h"
78 #include "canvas/text.h"
80 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_time_axis.h"
110 #include "mixer_strip.h"
111 #include "mixer_ui.h"
112 #include "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "tempo_lines.h"
121 #include "time_axis_view.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , videotl_label (_("Video Timeline"))
250 , edit_packer (4, 4, true)
252 /* the values here don't matter: layout widgets
253 reset them as needed.
256 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
257 , horizontal_adjustment (0.0, 0.0, 1e16)
258 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
260 , controls_layout (unused_adjustment, vertical_adjustment)
262 /* tool bar related */
264 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
265 , toolbar_selection_clock_table (2,3)
266 , _mouse_mode_tearoff (0)
267 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
275 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
276 , meters_running(false)
277 , _pending_locate_request (false)
278 , _pending_initial_locate (false)
279 , _last_cut_copy_source_track (0)
281 , _region_selection_change_updates_region_list (true)
282 , _following_mixer_selection (false)
283 , _control_point_toggled_on_press (false)
284 , _stepping_axis_view (0)
288 /* we are a singleton */
290 PublicEditor::_instance = this;
294 selection = new Selection (this);
295 cut_buffer = new Selection (this);
297 clicked_regionview = 0;
298 clicked_axisview = 0;
299 clicked_routeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 build_edit_mode_menu();
317 build_zoom_focus_menu();
318 build_track_count_menu();
319 build_snap_mode_menu();
320 build_snap_type_menu();
321 build_edit_point_menu();
323 snap_threshold = 5.0;
324 bbt_beat_subdivision = 4;
325 _visible_canvas_width = 0;
326 _visible_canvas_height = 0;
327 autoscroll_horizontal_allowed = false;
328 autoscroll_vertical_allowed = false;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
377 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
378 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
379 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
380 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
382 zoom_focus = ZoomFocusLeft;
383 _edit_point = EditAtMouse;
384 _internal_editing = false;
385 current_canvas_cursor = 0;
386 _visible_track_count = 16;
388 samples_per_pixel = 2048; /* too early to use reset_zoom () */
390 _scroll_callbacks = 0;
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorRulerLabel");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorRulerLabel");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorRulerLabel");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorRulerLabel");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorRulerLabel");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorRulerLabel");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 if (Profile->get_trx()) {
434 mark_label.set_text (_("Markers"));
436 mark_label.set_name ("EditorRulerLabel");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
441 mark_label.set_no_show_all();
443 cd_mark_label.set_name ("EditorRulerLabel");
444 cd_mark_label.set_size_request (-1, (int)timebar_height);
445 cd_mark_label.set_alignment (1.0, 0.5);
446 cd_mark_label.set_padding (5,0);
447 cd_mark_label.hide();
448 cd_mark_label.set_no_show_all();
450 videotl_bar_height = 4;
451 videotl_label.set_name ("EditorRulerLabel");
452 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
453 videotl_label.set_alignment (1.0, 0.5);
454 videotl_label.set_padding (5,0);
455 videotl_label.hide();
456 videotl_label.set_no_show_all();
458 range_mark_label.set_name ("EditorRulerLabel");
459 range_mark_label.set_size_request (-1, (int)timebar_height);
460 range_mark_label.set_alignment (1.0, 0.5);
461 range_mark_label.set_padding (5,0);
462 range_mark_label.hide();
463 range_mark_label.set_no_show_all();
465 transport_mark_label.set_name ("EditorRulerLabel");
466 transport_mark_label.set_size_request (-1, (int)timebar_height);
467 transport_mark_label.set_alignment (1.0, 0.5);
468 transport_mark_label.set_padding (5,0);
469 transport_mark_label.hide();
470 transport_mark_label.set_no_show_all();
472 initialize_rulers ();
473 initialize_canvas ();
475 _summary = new EditorSummary (this);
477 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
478 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
480 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
482 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
483 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
485 edit_controls_vbox.set_spacing (0);
486 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
487 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
489 HBox* h = manage (new HBox);
490 _group_tabs = new EditorGroupTabs (this);
491 if (!ARDOUR::Profile->get_trx()) {
492 h->pack_start (*_group_tabs, PACK_SHRINK);
494 h->pack_start (edit_controls_vbox);
495 controls_layout.add (*h);
497 controls_layout.set_name ("EditControlsBase");
498 controls_layout.add_events (Gdk::SCROLL_MASK);
499 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
501 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
502 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
504 _cursors = new MouseCursors;
506 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
508 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
509 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
510 pad_line_1->set_outline_color (0xFF0000FF);
516 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
517 time_canvas_vbox.set_size_request (-1, -1);
519 ruler_label_event_box.add (ruler_label_vbox);
520 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
521 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
523 time_bars_event_box.add (time_bars_vbox);
524 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
525 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
527 time_canvas_event_box.add (time_canvas_vbox);
528 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
530 edit_packer.set_col_spacings (0);
531 edit_packer.set_row_spacings (0);
532 edit_packer.set_homogeneous (false);
533 edit_packer.set_border_width (0);
534 edit_packer.set_name ("EditorWindow");
536 /* labels for the rulers */
537 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
538 /* labels for the marker "tracks" (time bars) */
539 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
541 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
543 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
544 /* time bars canvas */
545 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
547 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
549 bottom_hbox.set_border_width (2);
550 bottom_hbox.set_spacing (3);
552 _route_groups = new EditorRouteGroups (this);
553 _routes = new EditorRoutes (this);
554 _regions = new EditorRegions (this);
555 _snapshots = new EditorSnapshots (this);
556 _locations = new EditorLocations (this);
558 add_notebook_page (_("Regions"), _regions->widget ());
559 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
560 add_notebook_page (_("Snapshots"), _snapshots->widget ());
561 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
562 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
564 _the_notebook.set_show_tabs (true);
565 _the_notebook.set_scrollable (true);
566 _the_notebook.popup_disable ();
567 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
568 _the_notebook.show_all ();
570 _notebook_shrunk = false;
572 editor_summary_pane.pack1(edit_packer);
574 Button* summary_arrows_left_left = manage (new Button);
575 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
576 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
577 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
579 Button* summary_arrows_left_right = manage (new Button);
580 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
581 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
582 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
584 VBox* summary_arrows_left = manage (new VBox);
585 summary_arrows_left->pack_start (*summary_arrows_left_left);
586 summary_arrows_left->pack_start (*summary_arrows_left_right);
588 Button* summary_arrows_right_up = manage (new Button);
589 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
590 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
591 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
593 Button* summary_arrows_right_down = manage (new Button);
594 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
595 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
596 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
598 VBox* summary_arrows_right = manage (new VBox);
599 summary_arrows_right->pack_start (*summary_arrows_right_up);
600 summary_arrows_right->pack_start (*summary_arrows_right_down);
602 Frame* summary_frame = manage (new Frame);
603 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
605 summary_frame->add (*_summary);
606 summary_frame->show ();
608 _summary_hbox.pack_start (*summary_arrows_left, false, false);
609 _summary_hbox.pack_start (*summary_frame, true, true);
610 _summary_hbox.pack_start (*summary_arrows_right, false, false);
612 if (!ARDOUR::Profile->get_trx()) {
613 editor_summary_pane.pack2 (_summary_hbox);
616 edit_pane.pack1 (editor_summary_pane, true, true);
617 if (!ARDOUR::Profile->get_trx()) {
618 edit_pane.pack2 (_the_notebook, false, true);
621 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
623 /* XXX: editor_summary_pane might need similar to the edit_pane */
625 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
627 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
628 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
630 top_hbox.pack_start (toolbar_frame);
632 HBox *hbox = manage (new HBox);
633 hbox->pack_start (edit_pane, true, true);
635 global_vpacker.pack_start (top_hbox, false, false);
636 global_vpacker.pack_start (*hbox, true, true);
638 global_hpacker.pack_start (global_vpacker, true, true);
640 set_name ("EditorWindow");
641 add_accel_group (ActionManager::ui_manager->get_accel_group());
643 status_bar_hpacker.show ();
645 vpacker.pack_end (status_bar_hpacker, false, false);
646 vpacker.pack_end (global_hpacker, true, true);
648 /* register actions now so that set_state() can find them and set toggles/checks etc */
651 /* when we start using our own keybinding system for the editor, this
652 * will be uncommented
658 set_zoom_focus (zoom_focus);
659 set_visible_track_count (_visible_track_count);
660 _snap_type = SnapToBeat;
661 set_snap_to (_snap_type);
662 _snap_mode = SnapOff;
663 set_snap_mode (_snap_mode);
664 set_mouse_mode (MouseObject, true);
665 pre_internal_mouse_mode = MouseObject;
666 pre_internal_snap_type = _snap_type;
667 pre_internal_snap_mode = _snap_mode;
668 internal_snap_type = _snap_type;
669 internal_snap_mode = _snap_mode;
670 set_edit_point_preference (EditAtMouse, true);
672 _playlist_selector = new PlaylistSelector();
673 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
675 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
679 nudge_forward_button.set_name ("nudge button");
680 // nudge_forward_button.add_elements (ArdourButton::Inset);
681 nudge_forward_button.set_image(::get_icon("nudge_right"));
683 nudge_backward_button.set_name ("nudge button");
684 // nudge_backward_button.add_elements (ArdourButton::Inset);
685 nudge_backward_button.set_image(::get_icon("nudge_left"));
687 fade_context_menu.set_name ("ArdourContextMenu");
689 /* icons, titles, WM stuff */
691 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
692 Glib::RefPtr<Gdk::Pixbuf> icon;
694 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
695 window_icons.push_back (icon);
697 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
698 window_icons.push_back (icon);
700 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
701 window_icons.push_back (icon);
703 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
704 window_icons.push_back (icon);
706 if (!window_icons.empty()) {
707 // set_icon_list (window_icons);
708 set_default_icon_list (window_icons);
711 WindowTitle title(Glib::get_application_name());
712 title += _("Editor");
713 set_title (title.get_string());
714 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
717 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
719 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
720 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
722 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
724 /* allow external control surfaces/protocols to do various things */
726 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
727 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
728 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
729 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
730 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
731 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
732 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
733 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
734 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
735 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
736 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
737 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
738 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
739 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
741 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
742 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
743 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
744 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
745 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
747 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
749 /* problematic: has to return a value and thus cannot be x-thread */
751 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
753 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
755 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
757 _ignore_region_action = false;
758 _last_region_menu_was_main = false;
759 _popup_region_menu_item = 0;
761 _show_marker_lines = false;
762 _over_region_trim_target = false;
764 /* Button bindings */
766 button_bindings = new Bindings;
768 XMLNode* node = button_settings();
770 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
771 button_bindings->load (**i);
778 setup_fade_images ();
783 delete button_bindings;
785 delete _route_groups;
786 delete _time_bars_canvas_viewport;
787 delete _track_canvas_viewport;
792 Editor::button_settings () const
794 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
795 XMLNode* node = find_named_node (*settings, X_("Buttons"));
798 node = new XMLNode (X_("Buttons"));
805 Editor::add_toplevel_controls (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::get_smart_mode () const
814 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
818 Editor::catch_vanishing_regionview (RegionView *rv)
820 /* note: the selection will take care of the vanishing
821 audioregionview by itself.
824 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
828 if (clicked_regionview == rv) {
829 clicked_regionview = 0;
832 if (entered_regionview == rv) {
833 set_entered_regionview (0);
836 if (!_all_region_actions_sensitized) {
837 sensitize_all_region_actions (true);
840 _over_region_trim_target = false;
844 Editor::set_entered_regionview (RegionView* rv)
846 if (rv == entered_regionview) {
850 if (entered_regionview) {
851 entered_regionview->exited ();
854 if ((entered_regionview = rv) != 0) {
855 entered_regionview->entered (internal_editing ());
858 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
859 /* This RegionView entry might have changed what region actions
860 are allowed, so sensitize them all in case a key is pressed.
862 sensitize_all_region_actions (true);
867 Editor::set_entered_track (TimeAxisView* tav)
870 entered_track->exited ();
873 if ((entered_track = tav) != 0) {
874 entered_track->entered ();
879 Editor::show_window ()
881 if (!is_visible ()) {
884 /* XXX: this is a bit unfortunate; it would probably
885 be nicer if we could just call show () above rather
886 than needing the show_all ()
889 /* re-hide stuff if necessary */
890 editor_list_button_toggled ();
891 parameter_changed ("show-summary");
892 parameter_changed ("show-group-tabs");
893 parameter_changed ("show-zoom-tools");
895 /* now reset all audio_time_axis heights, because widgets might need
901 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
902 tv = (static_cast<TimeAxisView*>(*i));
906 if (current_mixer_strip) {
907 current_mixer_strip->hide_things ();
908 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
916 Editor::instant_save ()
918 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
923 _session->add_instant_xml(get_state());
925 Config->add_instant_xml(get_state());
930 Editor::zoom_adjustment_changed ()
936 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
937 bool clamped = clamp_samples_per_pixel (fpu);
940 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
947 Editor::control_vertical_zoom_in_all ()
949 tav_zoom_smooth (false, true);
953 Editor::control_vertical_zoom_out_all ()
955 tav_zoom_smooth (true, true);
959 Editor::control_vertical_zoom_in_selected ()
961 tav_zoom_smooth (false, false);
965 Editor::control_vertical_zoom_out_selected ()
967 tav_zoom_smooth (true, false);
971 Editor::control_view (uint32_t view)
973 goto_visual_state (view);
977 Editor::control_unselect ()
979 selection->clear_tracks ();
983 Editor::control_select (uint32_t rid, Selection::Operation op)
985 /* handles the (static) signal from the ControlProtocol class that
986 * requests setting the selected track to a given RID
993 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
999 TimeAxisView* tav = axis_view_from_route (r);
1003 case Selection::Add:
1004 selection->add (tav);
1006 case Selection::Toggle:
1007 selection->toggle (tav);
1009 case Selection::Extend:
1011 case Selection::Set:
1012 selection->set (tav);
1016 selection->clear_tracks ();
1021 Editor::control_step_tracks_up ()
1023 scroll_tracks_up_line ();
1027 Editor::control_step_tracks_down ()
1029 scroll_tracks_down_line ();
1033 Editor::control_scroll (float fraction)
1035 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1041 double step = fraction * current_page_samples();
1044 _control_scroll_target is an optional<T>
1046 it acts like a pointer to an framepos_t, with
1047 a operator conversion to boolean to check
1048 that it has a value could possibly use
1049 playhead_cursor->current_frame to store the
1050 value and a boolean in the class to know
1051 when it's out of date
1054 if (!_control_scroll_target) {
1055 _control_scroll_target = _session->transport_frame();
1056 _dragging_playhead = true;
1059 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1060 *_control_scroll_target = 0;
1061 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1062 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1064 *_control_scroll_target += (framepos_t) floor (step);
1067 /* move visuals, we'll catch up with it later */
1069 playhead_cursor->set_position (*_control_scroll_target);
1070 UpdateAllTransportClocks (*_control_scroll_target);
1072 if (*_control_scroll_target > (current_page_samples() / 2)) {
1073 /* try to center PH in window */
1074 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1080 Now we do a timeout to actually bring the session to the right place
1081 according to the playhead. This is to avoid reading disk buffers on every
1082 call to control_scroll, which is driven by ScrollTimeline and therefore
1083 probably by a control surface wheel which can generate lots of events.
1085 /* cancel the existing timeout */
1087 control_scroll_connection.disconnect ();
1089 /* add the next timeout */
1091 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1095 Editor::deferred_control_scroll (framepos_t /*target*/)
1097 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1098 // reset for next stream
1099 _control_scroll_target = boost::none;
1100 _dragging_playhead = false;
1105 Editor::access_action (std::string action_group, std::string action_item)
1111 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1114 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1122 Editor::on_realize ()
1124 Window::on_realize ();
1129 Editor::map_position_change (framepos_t frame)
1131 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1133 if (_session == 0) {
1137 if (_follow_playhead) {
1138 center_screen (frame);
1141 playhead_cursor->set_position (frame);
1145 Editor::center_screen (framepos_t frame)
1147 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1149 /* if we're off the page, then scroll.
1152 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1153 center_screen_internal (frame, page);
1158 Editor::center_screen_internal (framepos_t frame, float page)
1163 frame -= (framepos_t) page;
1168 reset_x_origin (frame);
1173 Editor::update_title ()
1175 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1178 bool dirty = _session->dirty();
1180 string session_name;
1182 if (_session->snap_name() != _session->name()) {
1183 session_name = _session->snap_name();
1185 session_name = _session->name();
1189 session_name = "*" + session_name;
1192 WindowTitle title(session_name);
1193 title += Glib::get_application_name();
1194 set_title (title.get_string());
1196 /* ::session_going_away() will have taken care of it */
1201 Editor::set_session (Session *t)
1203 SessionHandlePtr::set_session (t);
1209 zoom_range_clock->set_session (_session);
1210 _playlist_selector->set_session (_session);
1211 nudge_clock->set_session (_session);
1212 _summary->set_session (_session);
1213 _group_tabs->set_session (_session);
1214 _route_groups->set_session (_session);
1215 _regions->set_session (_session);
1216 _snapshots->set_session (_session);
1217 _routes->set_session (_session);
1218 _locations->set_session (_session);
1220 if (rhythm_ferret) {
1221 rhythm_ferret->set_session (_session);
1224 if (analysis_window) {
1225 analysis_window->set_session (_session);
1229 sfbrowser->set_session (_session);
1232 compute_fixed_ruler_scale ();
1234 /* Make sure we have auto loop and auto punch ranges */
1236 Location* loc = _session->locations()->auto_loop_location();
1238 loc->set_name (_("Loop"));
1241 loc = _session->locations()->auto_punch_location();
1244 loc->set_name (_("Punch"));
1247 refresh_location_display ();
1249 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1250 the selected Marker; this needs the LocationMarker list to be available.
1252 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1253 set_state (*node, Stateful::loading_state_version);
1255 /* catch up with the playhead */
1257 _session->request_locate (playhead_cursor->current_frame ());
1258 _pending_initial_locate = true;
1262 /* These signals can all be emitted by a non-GUI thread. Therefore the
1263 handlers for them must not attempt to directly interact with the GUI,
1264 but use PBD::Signal<T>::connect() which accepts an event loop
1265 ("context") where the handler will be asked to run.
1268 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1269 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1270 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1271 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1272 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1273 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1274 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1275 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1276 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1277 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1278 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1279 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1281 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1283 playhead_cursor->show ();
1285 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1286 Config->map_parameters (pc);
1287 _session->config.map_parameters (pc);
1289 restore_ruler_visibility ();
1290 //tempo_map_changed (PropertyChange (0));
1291 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1294 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1297 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1298 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1301 switch (_snap_type) {
1302 case SnapToRegionStart:
1303 case SnapToRegionEnd:
1304 case SnapToRegionSync:
1305 case SnapToRegionBoundary:
1306 build_region_boundary_cache ();
1313 /* register for undo history */
1314 _session->register_with_memento_command_factory(id(), this);
1316 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1318 start_updating_meters ();
1322 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1324 if (a->get_name() == "RegionMenu") {
1325 /* When the main menu's region menu is opened, we setup the actions so that they look right
1326 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1327 so we resensitize all region actions when the entered regionview or the region selection
1328 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1329 happens after the region context menu is opened. So we set a flag here, too.
1333 sensitize_the_right_region_actions ();
1334 _last_region_menu_was_main = true;
1339 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1341 using namespace Menu_Helpers;
1343 void (Editor::*emf)(FadeShape);
1344 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1347 images = &_xfade_in_images;
1348 emf = &Editor::set_fade_in_shape;
1350 images = &_xfade_out_images;
1351 emf = &Editor::set_fade_out_shape;
1356 _("Linear (for highly correlated material)"),
1357 *(*images)[FadeLinear],
1358 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1362 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1366 _("Constant power"),
1367 *(*images)[FadeConstantPower],
1368 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1371 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1376 *(*images)[FadeSymmetric],
1377 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1381 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1386 *(*images)[FadeSlow],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *(*images)[FadeFast],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1399 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402 /** Pop up a context menu for when the user clicks on a start crossfade */
1404 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1406 using namespace Menu_Helpers;
1408 MenuList& items (xfade_in_context_menu.items());
1410 if (items.empty()) {
1411 fill_xfade_menu (items, true);
1414 xfade_in_context_menu.popup (button, time);
1417 /** Pop up a context menu for when the user clicks on an end crossfade */
1419 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1421 using namespace Menu_Helpers;
1423 MenuList& items (xfade_out_context_menu.items());
1425 if (items.empty()) {
1426 fill_xfade_menu (items, false);
1429 xfade_out_context_menu.popup (button, time);
1433 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1435 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1437 using namespace Menu_Helpers;
1438 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1441 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1445 MenuList& items (fade_context_menu.items());
1448 switch (item_type) {
1450 case FadeInHandleItem:
1451 if (arv->audio_region()->fade_in_active()) {
1452 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1454 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1457 items.push_back (SeparatorElem());
1459 if (Profile->get_sae()) {
1461 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1462 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1469 *_fade_in_images[FadeLinear],
1470 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *_fade_in_images[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *_fade_in_images[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *_fade_in_images[FadeSymmetric],
1498 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1503 _("Constant power"),
1504 *_fade_in_images[FadeConstantPower],
1505 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1514 case FadeOutHandleItem:
1515 if (arv->audio_region()->fade_out_active()) {
1516 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1518 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1521 items.push_back (SeparatorElem());
1523 if (Profile->get_sae()) {
1524 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1525 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1531 *_fade_out_images[FadeLinear],
1532 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1536 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1541 *_fade_out_images[FadeSlow],
1542 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1545 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1550 *_fade_out_images[FadeFast],
1551 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1554 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1559 *_fade_out_images[FadeSymmetric],
1560 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1565 _("Constant power"),
1566 *_fade_out_images[FadeConstantPower],
1567 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1570 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1576 fatal << _("programming error: ")
1577 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1582 fade_context_menu.popup (button, time);
1586 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1588 using namespace Menu_Helpers;
1589 Menu* (Editor::*build_menu_function)();
1592 switch (item_type) {
1594 case RegionViewName:
1595 case RegionViewNameHighlight:
1596 case LeftFrameHandle:
1597 case RightFrameHandle:
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_region_context_menu;
1606 if (with_selection) {
1607 build_menu_function = &Editor::build_track_selection_context_menu;
1609 build_menu_function = &Editor::build_track_context_menu;
1614 if (clicked_routeview->track()) {
1615 build_menu_function = &Editor::build_track_context_menu;
1617 build_menu_function = &Editor::build_track_bus_context_menu;
1622 /* probably shouldn't happen but if it does, we don't care */
1626 menu = (this->*build_menu_function)();
1627 menu->set_name ("ArdourContextMenu");
1629 /* now handle specific situations */
1631 switch (item_type) {
1633 case RegionViewName:
1634 case RegionViewNameHighlight:
1635 case LeftFrameHandle:
1636 case RightFrameHandle:
1637 if (!with_selection) {
1638 if (region_edit_menu_split_item) {
1639 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1642 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1645 if (region_edit_menu_split_multichannel_item) {
1646 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1647 region_edit_menu_split_multichannel_item->set_sensitive (true);
1649 region_edit_menu_split_multichannel_item->set_sensitive (false);
1662 /* probably shouldn't happen but if it does, we don't care */
1666 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1668 /* Bounce to disk */
1670 using namespace Menu_Helpers;
1671 MenuList& edit_items = menu->items();
1673 edit_items.push_back (SeparatorElem());
1675 switch (clicked_routeview->audio_track()->freeze_state()) {
1676 case AudioTrack::NoFreeze:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1680 case AudioTrack::Frozen:
1681 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1684 case AudioTrack::UnFrozen:
1685 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1691 if (item_type == StreamItem && clicked_routeview) {
1692 clicked_routeview->build_underlay_menu(menu);
1695 /* When the region menu is opened, we setup the actions so that they look right
1698 sensitize_the_right_region_actions ();
1699 _last_region_menu_was_main = false;
1701 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1702 menu->popup (button, time);
1706 Editor::build_track_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_dstream_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_bus_context_menu ()
1720 using namespace Menu_Helpers;
1722 MenuList& edit_items = track_context_menu.items();
1725 add_bus_context_items (edit_items);
1726 return &track_context_menu;
1730 Editor::build_track_region_context_menu ()
1732 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_region_context_menu.items();
1736 /* we've just cleared the track region context menu, so the menu that these
1737 two items were on will have disappeared; stop them dangling.
1739 region_edit_menu_split_item = 0;
1740 region_edit_menu_split_multichannel_item = 0;
1742 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1745 boost::shared_ptr<Track> tr;
1746 boost::shared_ptr<Playlist> pl;
1748 if ((tr = rtv->track())) {
1749 add_region_context_items (edit_items, tr);
1753 add_dstream_context_items (edit_items);
1755 return &track_region_context_menu;
1759 Editor::analyze_region_selection ()
1761 if (analysis_window == 0) {
1762 analysis_window = new AnalysisWindow();
1765 analysis_window->set_session(_session);
1767 analysis_window->show_all();
1770 analysis_window->set_regionmode();
1771 analysis_window->analyze();
1773 analysis_window->present();
1777 Editor::analyze_range_selection()
1779 if (analysis_window == 0) {
1780 analysis_window = new AnalysisWindow();
1783 analysis_window->set_session(_session);
1785 analysis_window->show_all();
1788 analysis_window->set_rangemode();
1789 analysis_window->analyze();
1791 analysis_window->present();
1795 Editor::build_track_selection_context_menu ()
1797 using namespace Menu_Helpers;
1798 MenuList& edit_items = track_selection_context_menu.items();
1799 edit_items.clear ();
1801 add_selection_context_items (edit_items);
1802 // edit_items.push_back (SeparatorElem());
1803 // add_dstream_context_items (edit_items);
1805 return &track_selection_context_menu;
1809 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1811 using namespace Menu_Helpers;
1813 /* OK, stick the region submenu at the top of the list, and then add
1817 RegionSelection rs = get_regions_from_selection_and_entered ();
1819 string::size_type pos = 0;
1820 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1822 /* we have to hack up the region name because "_" has a special
1823 meaning for menu titles.
1826 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1827 menu_item_name.replace (pos, 1, "__");
1831 if (_popup_region_menu_item == 0) {
1832 _popup_region_menu_item = new MenuItem (menu_item_name);
1833 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1834 _popup_region_menu_item->show ();
1836 _popup_region_menu_item->set_label (menu_item_name);
1839 const framepos_t position = get_preferred_edit_position (false, true);
1841 edit_items.push_back (*_popup_region_menu_item);
1842 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1843 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1845 edit_items.push_back (SeparatorElem());
1848 /** Add context menu items relevant to selection ranges.
1849 * @param edit_items List to add the items to.
1852 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1854 using namespace Menu_Helpers;
1856 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1857 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1862 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (
1866 _("Move Range Start to Previous Region Boundary"),
1867 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1871 edit_items.push_back (
1873 _("Move Range Start to Next Region Boundary"),
1874 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1878 edit_items.push_back (
1880 _("Move Range End to Previous Region Boundary"),
1881 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1885 edit_items.push_back (
1887 _("Move Range End to Next Region Boundary"),
1888 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1892 edit_items.push_back (SeparatorElem());
1893 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1894 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1901 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1908 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1909 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1913 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1915 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1916 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1917 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1918 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1924 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1930 Menu *play_menu = manage (new Menu);
1931 MenuList& play_items = play_menu->items();
1932 play_menu->set_name ("ArdourContextMenu");
1934 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1935 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1936 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1937 play_items.push_back (SeparatorElem());
1938 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1940 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1944 Menu *select_menu = manage (new Menu);
1945 MenuList& select_items = select_menu->items();
1946 select_menu->set_name ("ArdourContextMenu");
1948 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1951 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1954 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1957 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1958 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1959 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1960 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1961 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1962 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1964 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1968 Menu *cutnpaste_menu = manage (new Menu);
1969 MenuList& cutnpaste_items = cutnpaste_menu->items();
1970 cutnpaste_menu->set_name ("ArdourContextMenu");
1972 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1973 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1974 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1976 cutnpaste_items.push_back (SeparatorElem());
1978 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1979 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1981 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1983 /* Adding new material */
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1987 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1991 Menu *nudge_menu = manage (new Menu());
1992 MenuList& nudge_items = nudge_menu->items();
1993 nudge_menu->set_name ("ArdourContextMenu");
1995 edit_items.push_back (SeparatorElem());
1996 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2001 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2005 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2007 using namespace Menu_Helpers;
2011 Menu *play_menu = manage (new Menu);
2012 MenuList& play_items = play_menu->items();
2013 play_menu->set_name ("ArdourContextMenu");
2015 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2016 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2017 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2021 Menu *select_menu = manage (new Menu);
2022 MenuList& select_items = select_menu->items();
2023 select_menu->set_name ("ArdourContextMenu");
2025 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2027 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2028 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2029 select_items.push_back (SeparatorElem());
2030 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2031 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2032 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2039 Menu *cutnpaste_menu = manage (new Menu);
2040 MenuList& cutnpaste_items = cutnpaste_menu->items();
2041 cutnpaste_menu->set_name ("ArdourContextMenu");
2043 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2044 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2045 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2047 Menu *nudge_menu = manage (new Menu());
2048 MenuList& nudge_items = nudge_menu->items();
2049 nudge_menu->set_name ("ArdourContextMenu");
2051 edit_items.push_back (SeparatorElem());
2052 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2057 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2061 Editor::snap_type() const
2067 Editor::snap_mode() const
2073 Editor::set_snap_to (SnapType st)
2075 unsigned int snap_ind = (unsigned int)st;
2079 if (snap_ind > snap_type_strings.size() - 1) {
2081 _snap_type = (SnapType)snap_ind;
2084 string str = snap_type_strings[snap_ind];
2086 if (str != snap_type_selector.get_text()) {
2087 snap_type_selector.set_text (str);
2092 switch (_snap_type) {
2093 case SnapToBeatDiv128:
2094 case SnapToBeatDiv64:
2095 case SnapToBeatDiv32:
2096 case SnapToBeatDiv28:
2097 case SnapToBeatDiv24:
2098 case SnapToBeatDiv20:
2099 case SnapToBeatDiv16:
2100 case SnapToBeatDiv14:
2101 case SnapToBeatDiv12:
2102 case SnapToBeatDiv10:
2103 case SnapToBeatDiv8:
2104 case SnapToBeatDiv7:
2105 case SnapToBeatDiv6:
2106 case SnapToBeatDiv5:
2107 case SnapToBeatDiv4:
2108 case SnapToBeatDiv3:
2109 case SnapToBeatDiv2: {
2110 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2111 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2113 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2114 current_bbt_points_begin, current_bbt_points_end);
2115 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2116 current_bbt_points_begin, current_bbt_points_end);
2117 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2121 case SnapToRegionStart:
2122 case SnapToRegionEnd:
2123 case SnapToRegionSync:
2124 case SnapToRegionBoundary:
2125 build_region_boundary_cache ();
2133 SnapChanged (); /* EMIT SIGNAL */
2137 Editor::set_snap_mode (SnapMode mode)
2139 string str = snap_mode_strings[(int)mode];
2141 if (_internal_editing) {
2142 internal_snap_mode = mode;
2144 pre_internal_snap_mode = mode;
2149 if (str != snap_mode_selector.get_text ()) {
2150 snap_mode_selector.set_text (str);
2156 Editor::set_edit_point_preference (EditPoint ep, bool force)
2158 bool changed = (_edit_point != ep);
2161 string str = edit_point_strings[(int)ep];
2163 if (str != edit_point_selector.get_text ()) {
2164 edit_point_selector.set_text (str);
2167 set_canvas_cursor ();
2169 if (!force && !changed) {
2173 const char* action=NULL;
2175 switch (_edit_point) {
2176 case EditAtPlayhead:
2177 action = "edit-at-playhead";
2179 case EditAtSelectedMarker:
2180 action = "edit-at-marker";
2183 action = "edit-at-mouse";
2187 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2189 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2193 bool in_track_canvas;
2195 if (!mouse_frame (foo, in_track_canvas)) {
2196 in_track_canvas = false;
2199 reset_canvas_action_sensitivity (in_track_canvas);
2205 Editor::set_state (const XMLNode& node, int /*version*/)
2207 const XMLProperty* prop;
2214 g.base_width = default_width;
2215 g.base_height = default_height;
2219 if ((geometry = find_named_node (node, "geometry")) != 0) {
2223 if ((prop = geometry->property("x_size")) == 0) {
2224 prop = geometry->property ("x-size");
2227 g.base_width = atoi(prop->value());
2229 if ((prop = geometry->property("y_size")) == 0) {
2230 prop = geometry->property ("y-size");
2233 g.base_height = atoi(prop->value());
2236 if ((prop = geometry->property ("x_pos")) == 0) {
2237 prop = geometry->property ("x-pos");
2240 x = atoi (prop->value());
2243 if ((prop = geometry->property ("y_pos")) == 0) {
2244 prop = geometry->property ("y-pos");
2247 y = atoi (prop->value());
2251 set_default_size (g.base_width, g.base_height);
2254 if (_session && (prop = node.property ("playhead"))) {
2256 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2257 playhead_cursor->set_position (pos);
2259 playhead_cursor->set_position (0);
2262 if ((prop = node.property ("mixer-width"))) {
2263 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2266 if ((prop = node.property ("zoom-focus"))) {
2267 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2270 if ((prop = node.property ("zoom"))) {
2271 /* older versions of ardour used floating point samples_per_pixel */
2272 double f = PBD::atof (prop->value());
2273 reset_zoom (llrintf (f));
2275 reset_zoom (samples_per_pixel);
2278 if ((prop = node.property ("visible-track-count"))) {
2279 set_visible_track_count (PBD::atoi (prop->value()));
2282 if ((prop = node.property ("snap-to"))) {
2283 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2286 if ((prop = node.property ("snap-mode"))) {
2287 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2290 if ((prop = node.property ("internal-snap-to"))) {
2291 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2294 if ((prop = node.property ("internal-snap-mode"))) {
2295 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2298 if ((prop = node.property ("pre-internal-snap-to"))) {
2299 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2303 if ((prop = node.property ("pre-internal-snap-mode"))) {
2304 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2307 if ((prop = node.property ("mouse-mode"))) {
2308 MouseMode m = str2mousemode(prop->value());
2309 set_mouse_mode (m, true);
2311 set_mouse_mode (MouseObject, true);
2314 if ((prop = node.property ("left-frame")) != 0) {
2316 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2320 reset_x_origin (pos);
2324 if ((prop = node.property ("y-origin")) != 0) {
2325 reset_y_origin (atof (prop->value ()));
2328 if ((prop = node.property ("internal-edit"))) {
2329 bool yn = string_is_affirmative (prop->value());
2330 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2332 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2333 tact->set_active (!yn);
2334 tact->set_active (yn);
2338 if ((prop = node.property ("join-object-range"))) {
2339 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2340 bool yn = string_is_affirmative (prop->value());
2342 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2343 tact->set_active (!yn);
2344 tact->set_active (yn);
2346 set_mouse_mode(mouse_mode, true);
2349 if ((prop = node.property ("edit-point"))) {
2350 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2353 if ((prop = node.property ("show-measures"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 _show_measures = yn;
2356 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2358 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2359 /* do it twice to force the change */
2360 tact->set_active (!yn);
2361 tact->set_active (yn);
2365 if ((prop = node.property ("follow-playhead"))) {
2366 bool yn = string_is_affirmative (prop->value());
2367 set_follow_playhead (yn);
2368 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2370 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2371 if (tact->get_active() != yn) {
2372 tact->set_active (yn);
2377 if ((prop = node.property ("stationary-playhead"))) {
2378 bool yn = string_is_affirmative (prop->value());
2379 set_stationary_playhead (yn);
2380 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2382 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2383 if (tact->get_active() != yn) {
2384 tact->set_active (yn);
2389 if ((prop = node.property ("region-list-sort-type"))) {
2390 RegionListSortType st;
2391 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2394 if ((prop = node.property ("show-editor-mixer"))) {
2396 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2399 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2400 bool yn = string_is_affirmative (prop->value());
2402 /* do it twice to force the change */
2404 tact->set_active (!yn);
2405 tact->set_active (yn);
2408 if ((prop = node.property ("show-editor-list"))) {
2410 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2413 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2414 bool yn = string_is_affirmative (prop->value());
2416 /* do it twice to force the change */
2418 tact->set_active (!yn);
2419 tact->set_active (yn);
2422 if ((prop = node.property (X_("editor-list-page")))) {
2423 _the_notebook.set_current_page (atoi (prop->value ()));
2426 if ((prop = node.property (X_("show-marker-lines")))) {
2427 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2429 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2430 bool yn = string_is_affirmative (prop->value ());
2432 tact->set_active (!yn);
2433 tact->set_active (yn);
2436 XMLNodeList children = node.children ();
2437 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2438 selection->set_state (**i, Stateful::current_state_version);
2439 _regions->set_state (**i);
2442 if ((prop = node.property ("maximised"))) {
2443 bool yn = string_is_affirmative (prop->value());
2444 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2446 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2447 bool fs = tact && tact->get_active();
2449 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2453 if ((prop = node.property ("nudge-clock-value"))) {
2455 sscanf (prop->value().c_str(), "%" PRId64, &f);
2456 nudge_clock->set (f);
2458 nudge_clock->set_mode (AudioClock::Timecode);
2459 nudge_clock->set (_session->frame_rate() * 5, true);
2466 Editor::get_state ()
2468 XMLNode* node = new XMLNode ("Editor");
2471 id().print (buf, sizeof (buf));
2472 node->add_property ("id", buf);
2474 if (is_realized()) {
2475 Glib::RefPtr<Gdk::Window> win = get_window();
2477 int x, y, width, height;
2478 win->get_root_origin(x, y);
2479 win->get_size(width, height);
2481 XMLNode* geometry = new XMLNode ("geometry");
2483 snprintf(buf, sizeof(buf), "%d", width);
2484 geometry->add_property("x-size", string(buf));
2485 snprintf(buf, sizeof(buf), "%d", height);
2486 geometry->add_property("y-size", string(buf));
2487 snprintf(buf, sizeof(buf), "%d", x);
2488 geometry->add_property("x-pos", string(buf));
2489 snprintf(buf, sizeof(buf), "%d", y);
2490 geometry->add_property("y-pos", string(buf));
2491 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2492 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2493 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2494 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2495 geometry->add_property("edit-vertical-pane-pos", string(buf));
2497 node->add_child_nocopy (*geometry);
2500 maybe_add_mixer_strip_width (*node);
2502 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2504 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2505 node->add_property ("zoom", buf);
2506 node->add_property ("snap-to", enum_2_string (_snap_type));
2507 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2508 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2509 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2510 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2511 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2512 node->add_property ("edit-point", enum_2_string (_edit_point));
2513 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2514 node->add_property ("visible-track-count", buf);
2516 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2517 node->add_property ("playhead", buf);
2518 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2519 node->add_property ("left-frame", buf);
2520 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2521 node->add_property ("y-origin", buf);
2523 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2524 node->add_property ("maximised", _maximised ? "yes" : "no");
2525 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2526 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2527 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2528 node->add_property ("mouse-mode", enum2str(mouse_mode));
2529 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2530 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2532 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2534 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2535 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2538 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2540 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2541 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2544 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2545 node->add_property (X_("editor-list-page"), buf);
2547 if (button_bindings) {
2548 XMLNode* bb = new XMLNode (X_("Buttons"));
2549 button_bindings->save (*bb);
2550 node->add_child_nocopy (*bb);
2553 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2555 node->add_child_nocopy (selection->get_state ());
2556 node->add_child_nocopy (_regions->get_state ());
2558 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2559 node->add_property ("nudge-clock-value", buf);
2566 /** @param y y offset from the top of all trackviews.
2567 * @return pair: TimeAxisView that y is over, layer index.
2568 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2569 * in stacked or expanded region display mode, otherwise 0.
2571 std::pair<TimeAxisView *, double>
2572 Editor::trackview_by_y_position (double y)
2574 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2576 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2582 return std::make_pair ( (TimeAxisView *) 0, 0);
2585 /** Snap a position to the grid, if appropriate, taking into account current
2586 * grid settings and also the state of any snap modifier keys that may be pressed.
2587 * @param start Position to snap.
2588 * @param event Event to get current key modifier information from, or 0.
2591 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2593 if (!_session || !event) {
2597 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2598 if (_snap_mode == SnapOff) {
2599 snap_to_internal (start, direction, for_mark);
2602 if (_snap_mode != SnapOff) {
2603 snap_to_internal (start, direction, for_mark);
2609 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2611 if (!_session || _snap_mode == SnapOff) {
2615 snap_to_internal (start, direction, for_mark);
2619 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2621 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2622 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2624 switch (_snap_type) {
2625 case SnapToTimecodeFrame:
2626 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2627 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2629 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2633 case SnapToTimecodeSeconds:
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start += _session->config.get_timecode_offset ();
2637 start -= _session->config.get_timecode_offset ();
2639 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2640 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2642 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2645 if (_session->config.get_timecode_offset_negative()) {
2646 start -= _session->config.get_timecode_offset ();
2648 start += _session->config.get_timecode_offset ();
2652 case SnapToTimecodeMinutes:
2653 if (_session->config.get_timecode_offset_negative()) {
2654 start += _session->config.get_timecode_offset ();
2656 start -= _session->config.get_timecode_offset ();
2658 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2659 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2661 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2663 if (_session->config.get_timecode_offset_negative()) {
2664 start -= _session->config.get_timecode_offset ();
2666 start += _session->config.get_timecode_offset ();
2670 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2676 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2678 const framepos_t one_second = _session->frame_rate();
2679 const framepos_t one_minute = _session->frame_rate() * 60;
2680 framepos_t presnap = start;
2684 switch (_snap_type) {
2685 case SnapToTimecodeFrame:
2686 case SnapToTimecodeSeconds:
2687 case SnapToTimecodeMinutes:
2688 return timecode_snap_to_internal (start, direction, for_mark);
2691 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2694 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2699 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2700 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2702 start = (framepos_t) floor ((double) start / one_second) * one_second;
2707 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2708 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2710 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2715 start = _session->tempo_map().round_to_bar (start, direction);
2719 start = _session->tempo_map().round_to_beat (start, direction);
2722 case SnapToBeatDiv128:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2725 case SnapToBeatDiv64:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2728 case SnapToBeatDiv32:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2731 case SnapToBeatDiv28:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2734 case SnapToBeatDiv24:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2737 case SnapToBeatDiv20:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2740 case SnapToBeatDiv16:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2743 case SnapToBeatDiv14:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2746 case SnapToBeatDiv12:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2749 case SnapToBeatDiv10:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2752 case SnapToBeatDiv8:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2755 case SnapToBeatDiv7:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2758 case SnapToBeatDiv6:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2761 case SnapToBeatDiv5:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2764 case SnapToBeatDiv4:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2767 case SnapToBeatDiv3:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2770 case SnapToBeatDiv2:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2779 _session->locations()->marks_either_side (start, before, after);
2781 if (before == max_framepos && after == max_framepos) {
2782 /* No marks to snap to, so just don't snap */
2784 } else if (before == max_framepos) {
2786 } else if (after == max_framepos) {
2788 } else if (before != max_framepos && after != max_framepos) {
2789 /* have before and after */
2790 if ((start - before) < (after - start)) {
2799 case SnapToRegionStart:
2800 case SnapToRegionEnd:
2801 case SnapToRegionSync:
2802 case SnapToRegionBoundary:
2803 if (!region_boundary_cache.empty()) {
2805 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2806 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2808 if (direction > 0) {
2809 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2811 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2814 if (next != region_boundary_cache.begin ()) {
2819 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2820 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2822 if (start > (p + n) / 2) {
2831 switch (_snap_mode) {
2837 if (presnap > start) {
2838 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2842 } else if (presnap < start) {
2843 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2849 /* handled at entry */
2857 Editor::setup_toolbar ()
2859 HBox* mode_box = manage(new HBox);
2860 mode_box->set_border_width (2);
2861 mode_box->set_spacing(4);
2863 HBox* mouse_mode_box = manage (new HBox);
2864 HBox* mouse_mode_hbox = manage (new HBox);
2865 VBox* mouse_mode_vbox = manage (new VBox);
2866 Alignment* mouse_mode_align = manage (new Alignment);
2868 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2869 // mouse_mode_size_group->add_widget (smart_mode_button);
2870 mouse_mode_size_group->add_widget (mouse_move_button);
2871 mouse_mode_size_group->add_widget (mouse_select_button);
2872 mouse_mode_size_group->add_widget (mouse_zoom_button);
2873 mouse_mode_size_group->add_widget (mouse_gain_button);
2874 mouse_mode_size_group->add_widget (mouse_timefx_button);
2875 mouse_mode_size_group->add_widget (mouse_audition_button);
2876 mouse_mode_size_group->add_widget (mouse_draw_button);
2877 mouse_mode_size_group->add_widget (internal_edit_button);
2879 /* make them just a bit bigger */
2880 mouse_move_button.set_size_request (-1, 30);
2882 mouse_mode_hbox->set_spacing (2);
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2892 if (!ARDOUR::Profile->get_trx()) {
2893 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2897 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2900 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2902 mouse_mode_align->add (*mouse_mode_vbox);
2903 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2905 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2907 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2908 if (!Profile->get_sae()) {
2909 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2911 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2913 edit_mode_selector.set_name ("mouse mode button");
2914 edit_mode_selector.set_size_request (65, -1);
2915 edit_mode_selector.add_elements (ArdourButton::Inset);
2917 if (!ARDOUR::Profile->get_trx()) {
2918 mode_box->pack_start (edit_mode_selector, false, false);
2920 mode_box->pack_start (*mouse_mode_box, false, false);
2922 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2923 _mouse_mode_tearoff->set_name ("MouseModeBase");
2924 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2926 if (Profile->get_sae()) {
2927 _mouse_mode_tearoff->set_can_be_torn_off (false);
2930 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window()));
2932 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_mouse_mode_tearoff->tearoff_window(), 1));
2934 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2935 &_mouse_mode_tearoff->tearoff_window()));
2936 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2937 &_mouse_mode_tearoff->tearoff_window(), 1));
2941 _zoom_box.set_spacing (2);
2942 _zoom_box.set_border_width (2);
2946 zoom_in_button.set_name ("zoom button");
2947 // zoom_in_button.add_elements ( ArdourButton::Inset );
2948 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2949 zoom_in_button.set_image(::get_icon ("zoom_in"));
2950 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2951 zoom_in_button.set_related_action (act);
2953 zoom_out_button.set_name ("zoom button");
2954 // zoom_out_button.add_elements ( ArdourButton::Inset );
2955 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2956 zoom_out_button.set_image(::get_icon ("zoom_out"));
2957 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2958 zoom_out_button.set_related_action (act);
2960 zoom_out_full_button.set_name ("zoom button");
2961 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2962 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2963 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2964 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2965 zoom_out_full_button.set_related_action (act);
2967 zoom_focus_selector.set_name ("zoom button");
2968 zoom_focus_selector.set_size_request (80, -1);
2969 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2971 if (!ARDOUR::Profile->get_trx()) {
2972 _zoom_box.pack_start (zoom_out_button, false, false);
2973 _zoom_box.pack_start (zoom_in_button, false, false);
2974 _zoom_box.pack_start (zoom_out_full_button, false, false);
2975 _zoom_box.pack_start (zoom_focus_selector, false, false);
2977 mode_box->pack_start (zoom_out_button, false, false);
2978 mode_box->pack_start (zoom_in_button, false, false);
2981 /* Track zoom buttons */
2982 visible_tracks_selector.set_name ("zoom button");
2983 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2984 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2986 tav_expand_button.set_name ("zoom button");
2987 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2988 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2989 tav_expand_button.set_size_request (-1, 20);
2990 tav_expand_button.set_image(::get_icon ("tav_exp"));
2991 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2992 tav_expand_button.set_related_action (act);
2994 tav_shrink_button.set_name ("zoom button");
2995 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2996 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2997 tav_shrink_button.set_size_request (-1, 20);
2998 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2999 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3000 tav_shrink_button.set_related_action (act);
3002 if (!ARDOUR::Profile->get_trx()) {
3003 _zoom_box.pack_start (visible_tracks_selector);
3005 _zoom_box.pack_start (tav_shrink_button);
3006 _zoom_box.pack_start (tav_expand_button);
3008 if (!ARDOUR::Profile->get_trx()) {
3009 _zoom_tearoff = manage (new TearOff (_zoom_box));
3011 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012 &_zoom_tearoff->tearoff_window()));
3013 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014 &_zoom_tearoff->tearoff_window(), 0));
3015 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3016 &_zoom_tearoff->tearoff_window()));
3017 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3018 &_zoom_tearoff->tearoff_window(), 0));
3021 snap_box.set_spacing (2);
3022 snap_box.set_border_width (2);
3024 snap_type_selector.set_name ("mouse mode button");
3025 snap_type_selector.set_size_request (140, -1);
3026 snap_type_selector.add_elements (ArdourButton::Inset);
3028 snap_mode_selector.set_name ("mouse mode button");
3029 snap_mode_selector.set_size_request (85, -1);
3030 snap_mode_selector.add_elements (ArdourButton::Inset);
3032 edit_point_selector.set_name ("mouse mode button");
3033 edit_point_selector.set_size_request (85, -1);
3034 edit_point_selector.add_elements (ArdourButton::Inset);
3036 snap_box.pack_start (snap_mode_selector, false, false);
3037 snap_box.pack_start (snap_type_selector, false, false);
3038 snap_box.pack_start (edit_point_selector, false, false);
3042 HBox *nudge_box = manage (new HBox);
3043 nudge_box->set_spacing (2);
3044 nudge_box->set_border_width (2);
3046 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3047 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3049 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3050 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3052 nudge_box->pack_start (nudge_backward_button, false, false);
3053 nudge_box->pack_start (nudge_forward_button, false, false);
3054 nudge_box->pack_start (*nudge_clock, false, false);
3057 /* Pack everything in... */
3059 HBox* hbox = manage (new HBox);
3060 hbox->set_spacing(10);
3062 _tools_tearoff = manage (new TearOff (*hbox));
3063 _tools_tearoff->set_name ("MouseModeBase");
3064 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3066 if (Profile->get_sae()) {
3067 _tools_tearoff->set_can_be_torn_off (false);
3070 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3071 &_tools_tearoff->tearoff_window()));
3072 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3073 &_tools_tearoff->tearoff_window(), 0));
3074 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3075 &_tools_tearoff->tearoff_window()));
3076 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3077 &_tools_tearoff->tearoff_window(), 0));
3079 toolbar_hbox.set_spacing (10);
3080 toolbar_hbox.set_border_width (1);
3082 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3083 if (!ARDOUR::Profile->get_trx()) {
3084 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3085 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3088 if (!ARDOUR::Profile->get_trx()) {
3089 hbox->pack_start (snap_box, false, false);
3090 if (!Profile->get_small_screen()) {
3091 hbox->pack_start (*nudge_box, false, false);
3093 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3096 hbox->pack_start (panic_box, false, false);
3100 toolbar_base.set_name ("ToolBarBase");
3101 toolbar_base.add (toolbar_hbox);
3103 _toolbar_viewport.add (toolbar_base);
3104 /* stick to the required height but allow width to vary if there's not enough room */
3105 _toolbar_viewport.set_size_request (1, -1);
3107 toolbar_frame.set_shadow_type (SHADOW_OUT);
3108 toolbar_frame.set_name ("BaseFrame");
3109 toolbar_frame.add (_toolbar_viewport);
3113 Editor::build_edit_point_menu ()
3115 using namespace Menu_Helpers;
3117 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3118 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3119 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3123 Editor::build_edit_mode_menu ()
3125 using namespace Menu_Helpers;
3127 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3128 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3129 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3133 Editor::build_snap_mode_menu ()
3135 using namespace Menu_Helpers;
3137 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3138 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3139 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3143 Editor::build_snap_type_menu ()
3145 using namespace Menu_Helpers;
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3180 Editor::setup_tooltips ()
3182 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3183 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3184 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3185 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3186 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3187 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3188 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3189 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3190 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3191 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3192 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3193 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3194 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3195 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3196 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3197 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3198 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3199 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3200 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3201 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3202 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3203 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3204 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3205 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3209 Editor::convert_drop_to_paths (
3210 vector<string>& paths,
3211 const RefPtr<Gdk::DragContext>& /*context*/,
3214 const SelectionData& data,
3218 if (_session == 0) {
3222 vector<string> uris = data.get_uris();
3226 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3227 are actually URI lists. So do it by hand.
3230 if (data.get_target() != "text/plain") {
3234 /* Parse the "uri-list" format that Nautilus provides,
3235 where each pathname is delimited by \r\n.
3237 THERE MAY BE NO NULL TERMINATING CHAR!!!
3240 string txt = data.get_text();
3244 p = (char *) malloc (txt.length() + 1);
3245 txt.copy (p, txt.length(), 0);
3246 p[txt.length()] = '\0';
3252 while (g_ascii_isspace (*p))
3256 while (*q && (*q != '\n') && (*q != '\r')) {
3263 while (q > p && g_ascii_isspace (*q))
3268 uris.push_back (string (p, q - p + 1));
3272 p = strchr (p, '\n');
3284 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3285 if ((*i).substr (0,7) == "file://") {
3286 paths.push_back (Glib::filename_from_uri (*i));
3294 Editor::new_tempo_section ()
3299 Editor::map_transport_state ()
3301 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3303 if (_session && _session->transport_stopped()) {
3304 have_pending_keyboard_selection = false;
3307 update_loop_range_view ();
3313 Editor::begin_reversible_command (string name)
3316 _session->begin_reversible_command (name);
3321 Editor::begin_reversible_command (GQuark q)
3324 _session->begin_reversible_command (q);
3329 Editor::commit_reversible_command ()
3332 _session->commit_reversible_command ();
3337 Editor::history_changed ()
3341 if (undo_action && _session) {
3342 if (_session->undo_depth() == 0) {
3343 label = S_("Command|Undo");
3345 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3347 undo_action->property_label() = label;
3350 if (redo_action && _session) {
3351 if (_session->redo_depth() == 0) {
3354 label = string_compose(_("Redo (%1)"), _session->next_redo());
3356 redo_action->property_label() = label;
3361 Editor::duplicate_range (bool with_dialog)
3365 RegionSelection rs = get_regions_from_selection_and_entered ();
3367 if ( selection->time.length() == 0 && rs.empty()) {
3373 ArdourDialog win (_("Duplicate"));
3374 Label label (_("Number of duplications:"));
3375 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3376 SpinButton spinner (adjustment, 0.0, 1);
3379 win.get_vbox()->set_spacing (12);
3380 win.get_vbox()->pack_start (hbox);
3381 hbox.set_border_width (6);
3382 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3384 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3385 place, visually. so do this by hand.
3388 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3389 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3390 spinner.grab_focus();
3396 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3397 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3398 win.set_default_response (RESPONSE_ACCEPT);
3400 spinner.grab_focus ();
3402 switch (win.run ()) {
3403 case RESPONSE_ACCEPT:
3409 times = adjustment.get_value();
3412 if ((current_mouse_mode() == Editing::MouseRange)) {
3413 if (selection->time.length()) {
3414 duplicate_selection (times);
3416 } else if (get_smart_mode()) {
3417 if (selection->time.length()) {
3418 duplicate_selection (times);
3420 duplicate_some_regions (rs, times);
3422 duplicate_some_regions (rs, times);
3427 Editor::set_edit_mode (EditMode m)
3429 Config->set_edit_mode (m);
3433 Editor::cycle_edit_mode ()
3435 switch (Config->get_edit_mode()) {
3437 if (Profile->get_sae()) {
3438 Config->set_edit_mode (Lock);
3440 Config->set_edit_mode (Splice);
3444 Config->set_edit_mode (Lock);
3447 Config->set_edit_mode (Slide);
3453 Editor::edit_mode_selection_done ( EditMode m )
3455 Config->set_edit_mode ( m );
3459 Editor::snap_type_selection_done (SnapType snaptype)
3461 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3463 ract->set_active ();
3468 Editor::snap_mode_selection_done (SnapMode mode)
3470 RefPtr<RadioAction> ract = snap_mode_action (mode);
3473 ract->set_active (true);
3478 Editor::cycle_edit_point (bool with_marker)
3480 switch (_edit_point) {
3482 set_edit_point_preference (EditAtPlayhead);
3484 case EditAtPlayhead:
3486 set_edit_point_preference (EditAtSelectedMarker);
3488 set_edit_point_preference (EditAtMouse);
3491 case EditAtSelectedMarker:
3492 set_edit_point_preference (EditAtMouse);
3498 Editor::edit_point_selection_done (EditPoint ep)
3500 set_edit_point_preference ( ep );
3504 Editor::build_zoom_focus_menu ()
3506 using namespace Menu_Helpers;
3508 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3509 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3510 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3511 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3512 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3513 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3517 Editor::zoom_focus_selection_done ( ZoomFocus f )
3519 RefPtr<RadioAction> ract = zoom_focus_action (f);
3521 ract->set_active ();
3526 Editor::build_track_count_menu ()
3528 using namespace Menu_Helpers;
3530 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3535 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3545 Editor::set_visible_track_count (int32_t n)
3547 _visible_track_count = n;
3549 /* if the canvas hasn't really been allocated any size yet, just
3550 record the desired number of visible tracks and return. when canvas
3551 allocation happens, we will get called again and then we can do the
3555 if (_visible_canvas_height <= 1) {
3562 if (_visible_track_count > 0) {
3563 h = _visible_canvas_height / _visible_track_count;
3564 std::ostringstream s;
3565 s << _visible_track_count;
3567 } else if (_visible_track_count == 0) {
3568 h = _visible_canvas_height / track_views.size();
3571 /* negative value means that the visible track count has
3572 been overridden by explicit track height changes.
3574 visible_tracks_selector.set_text (X_("*"));
3578 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3579 (*i)->set_height (h);
3582 if (str != visible_tracks_selector.get_text()) {
3583 visible_tracks_selector.set_text (str);
3588 Editor::override_visible_track_count ()
3590 _visible_track_count = -_visible_track_count;
3594 Editor::edit_controls_button_release (GdkEventButton* ev)
3596 if (Keyboard::is_context_menu_event (ev)) {
3597 ARDOUR_UI::instance()->add_route (this);
3598 } else if (ev->button == 1) {
3599 selection->clear_tracks ();
3606 Editor::mouse_select_button_release (GdkEventButton* ev)
3608 /* this handles just right-clicks */
3610 if (ev->button != 3) {
3618 Editor::set_zoom_focus (ZoomFocus f)
3620 string str = zoom_focus_strings[(int)f];
3622 if (str != zoom_focus_selector.get_text()) {
3623 zoom_focus_selector.set_text (str);
3626 if (zoom_focus != f) {
3633 Editor::cycle_zoom_focus ()
3635 switch (zoom_focus) {
3637 set_zoom_focus (ZoomFocusRight);
3639 case ZoomFocusRight:
3640 set_zoom_focus (ZoomFocusCenter);
3642 case ZoomFocusCenter:
3643 set_zoom_focus (ZoomFocusPlayhead);
3645 case ZoomFocusPlayhead:
3646 set_zoom_focus (ZoomFocusMouse);
3648 case ZoomFocusMouse:
3649 set_zoom_focus (ZoomFocusEdit);
3652 set_zoom_focus (ZoomFocusLeft);
3658 Editor::ensure_float (Window& win)
3660 win.set_transient_for (*this);
3664 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3666 /* recover or initialize pane positions. do this here rather than earlier because
3667 we don't want the positions to change the child allocations, which they seem to do.
3673 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3682 XMLNode* geometry = find_named_node (*node, "geometry");
3684 if (which == static_cast<Paned*> (&edit_pane)) {
3686 if (done & Horizontal) {
3690 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3691 _notebook_shrunk = string_is_affirmative (prop->value ());
3694 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3695 /* initial allocation is 90% to canvas, 10% to notebook */
3696 pos = (int) floor (alloc.get_width() * 0.90f);
3697 snprintf (buf, sizeof(buf), "%d", pos);
3699 pos = atoi (prop->value());
3702 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3703 edit_pane.set_position (pos);
3706 done = (Pane) (done | Horizontal);
3708 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3710 if (done & Vertical) {
3714 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3715 /* initial allocation is 90% to canvas, 10% to summary */
3716 pos = (int) floor (alloc.get_height() * 0.90f);
3717 snprintf (buf, sizeof(buf), "%d", pos);
3720 pos = atoi (prop->value());
3723 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3724 editor_summary_pane.set_position (pos);
3727 done = (Pane) (done | Vertical);
3732 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3734 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3735 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3736 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3737 top_hbox.remove (toolbar_frame);
3742 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3744 if (toolbar_frame.get_parent() == 0) {
3745 top_hbox.pack_end (toolbar_frame);
3750 Editor::set_show_measures (bool yn)
3752 if (_show_measures != yn) {
3755 if ((_show_measures = yn) == true) {
3757 tempo_lines->show();
3760 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3761 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3763 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3764 draw_measures (begin, end);
3772 Editor::toggle_follow_playhead ()
3774 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3776 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3777 set_follow_playhead (tact->get_active());
3781 /** @param yn true to follow playhead, otherwise false.
3782 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3785 Editor::set_follow_playhead (bool yn, bool catch_up)
3787 if (_follow_playhead != yn) {
3788 if ((_follow_playhead = yn) == true && catch_up) {
3790 reset_x_origin_to_follow_playhead ();
3797 Editor::toggle_stationary_playhead ()
3799 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3801 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3802 set_stationary_playhead (tact->get_active());
3807 Editor::set_stationary_playhead (bool yn)
3809 if (_stationary_playhead != yn) {
3810 if ((_stationary_playhead = yn) == true) {
3812 // FIXME need a 3.0 equivalent of this 2.X call
3813 // update_current_screen ();
3820 Editor::playlist_selector () const
3822 return *_playlist_selector;
3826 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3830 switch (_snap_type) {
3835 case SnapToBeatDiv128:
3838 case SnapToBeatDiv64:
3841 case SnapToBeatDiv32:
3844 case SnapToBeatDiv28:
3847 case SnapToBeatDiv24:
3850 case SnapToBeatDiv20:
3853 case SnapToBeatDiv16:
3856 case SnapToBeatDiv14:
3859 case SnapToBeatDiv12:
3862 case SnapToBeatDiv10:
3865 case SnapToBeatDiv8:
3868 case SnapToBeatDiv7:
3871 case SnapToBeatDiv6:
3874 case SnapToBeatDiv5:
3877 case SnapToBeatDiv4:
3880 case SnapToBeatDiv3:
3883 case SnapToBeatDiv2:
3889 return _session->tempo_map().meter_at (position).divisions_per_bar();
3894 case SnapToTimecodeFrame:
3895 case SnapToTimecodeSeconds:
3896 case SnapToTimecodeMinutes:
3899 case SnapToRegionStart:
3900 case SnapToRegionEnd:
3901 case SnapToRegionSync:
3902 case SnapToRegionBoundary:
3912 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3916 ret = nudge_clock->current_duration (pos);
3917 next = ret + 1; /* XXXX fix me */
3923 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3925 ArdourDialog dialog (_("Playlist Deletion"));
3926 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3927 "If it is kept, its audio files will not be cleaned.\n"
3928 "If it is deleted, audio files used by it alone will be cleaned."),
3931 dialog.set_position (WIN_POS_CENTER);
3932 dialog.get_vbox()->pack_start (label);
3936 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3937 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3938 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3940 switch (dialog.run ()) {
3941 case RESPONSE_ACCEPT:
3942 /* delete the playlist */
3946 case RESPONSE_REJECT:
3947 /* keep the playlist */
3959 Editor::audio_region_selection_covers (framepos_t where)
3961 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3962 if ((*a)->region()->covers (where)) {
3971 Editor::prepare_for_cleanup ()
3973 cut_buffer->clear_regions ();
3974 cut_buffer->clear_playlists ();
3976 selection->clear_regions ();
3977 selection->clear_playlists ();
3979 _regions->suspend_redisplay ();
3983 Editor::finish_cleanup ()
3985 _regions->resume_redisplay ();
3989 Editor::transport_loop_location()
3992 return _session->locations()->auto_loop_location();
3999 Editor::transport_punch_location()
4002 return _session->locations()->auto_punch_location();
4009 Editor::control_layout_scroll (GdkEventScroll* ev)
4011 if (Keyboard::some_magic_widget_has_focus()) {
4015 switch (ev->direction) {
4017 scroll_tracks_up_line ();
4021 case GDK_SCROLL_DOWN:
4022 scroll_tracks_down_line ();
4026 /* no left/right handling yet */
4034 Editor::session_state_saved (string)
4037 _snapshots->redisplay ();
4041 Editor::update_tearoff_visibility()
4043 bool visible = Config->get_keep_tearoffs();
4044 _mouse_mode_tearoff->set_visible (visible);
4045 _tools_tearoff->set_visible (visible);
4046 if (_zoom_tearoff) {
4047 _zoom_tearoff->set_visible (visible);
4052 Editor::maximise_editing_space ()
4064 Editor::restore_editing_space ()
4076 * Make new playlists for a given track and also any others that belong
4077 * to the same active route group with the `select' property.
4082 Editor::new_playlists (TimeAxisView* v)
4084 begin_reversible_command (_("new playlists"));
4085 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4086 _session->playlists->get (playlists);
4087 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4088 commit_reversible_command ();
4092 * Use a copy of the current playlist for a given track and also any others that belong
4093 * to the same active route group with the `select' property.
4098 Editor::copy_playlists (TimeAxisView* v)
4100 begin_reversible_command (_("copy playlists"));
4101 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4102 _session->playlists->get (playlists);
4103 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4104 commit_reversible_command ();
4107 /** Clear the current playlist for a given track and also any others that belong
4108 * to the same active route group with the `select' property.
4113 Editor::clear_playlists (TimeAxisView* v)
4115 begin_reversible_command (_("clear playlists"));
4116 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4117 _session->playlists->get (playlists);
4118 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4119 commit_reversible_command ();
4123 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4125 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4129 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4131 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4135 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4137 atv.clear_playlist ();
4141 Editor::on_key_press_event (GdkEventKey* ev)
4143 return key_press_focus_accelerator_handler (*this, ev);
4147 Editor::on_key_release_event (GdkEventKey* ev)
4149 return Gtk::Window::on_key_release_event (ev);
4150 // return key_press_focus_accelerator_handler (*this, ev);
4153 /** Queue up a change to the viewport x origin.
4154 * @param frame New x origin.
4157 Editor::reset_x_origin (framepos_t frame)
4159 pending_visual_change.add (VisualChange::TimeOrigin);
4160 pending_visual_change.time_origin = frame;
4161 ensure_visual_change_idle_handler ();
4165 Editor::reset_y_origin (double y)
4167 pending_visual_change.add (VisualChange::YOrigin);
4168 pending_visual_change.y_origin = y;
4169 ensure_visual_change_idle_handler ();
4173 Editor::reset_zoom (framecnt_t spp)
4175 clamp_samples_per_pixel (spp);
4177 if (spp == samples_per_pixel) {
4181 pending_visual_change.add (VisualChange::ZoomLevel);
4182 pending_visual_change.samples_per_pixel = spp;
4183 ensure_visual_change_idle_handler ();
4187 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4189 reset_x_origin (frame);
4192 if (!no_save_visual) {
4193 undo_visual_stack.push_back (current_visual_state(false));
4197 Editor::VisualState::VisualState (bool with_tracks)
4198 : gui_state (with_tracks ? new GUIObjectState : 0)
4202 Editor::VisualState::~VisualState ()
4207 Editor::VisualState*
4208 Editor::current_visual_state (bool with_tracks)
4210 VisualState* vs = new VisualState (with_tracks);
4211 vs->y_position = vertical_adjustment.get_value();
4212 vs->samples_per_pixel = samples_per_pixel;
4213 vs->leftmost_frame = leftmost_frame;
4214 vs->zoom_focus = zoom_focus;
4217 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4224 Editor::undo_visual_state ()
4226 if (undo_visual_stack.empty()) {
4230 VisualState* vs = undo_visual_stack.back();
4231 undo_visual_stack.pop_back();
4234 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4236 use_visual_state (*vs);
4240 Editor::redo_visual_state ()
4242 if (redo_visual_stack.empty()) {
4246 VisualState* vs = redo_visual_stack.back();
4247 redo_visual_stack.pop_back();
4249 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4251 use_visual_state (*vs);
4255 Editor::swap_visual_state ()
4257 if (undo_visual_stack.empty()) {
4258 redo_visual_state ();
4260 undo_visual_state ();
4265 Editor::use_visual_state (VisualState& vs)
4267 PBD::Unwinder<bool> nsv (no_save_visual, true);
4269 _routes->suspend_redisplay ();
4271 vertical_adjustment.set_value (vs.y_position);
4273 set_zoom_focus (vs.zoom_focus);
4274 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4277 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4279 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4280 (*i)->reset_visual_state ();
4284 _routes->update_visibility ();
4285 _routes->resume_redisplay ();
4288 /** This is the core function that controls the zoom level of the canvas. It is called
4289 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4290 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4293 Editor::set_samples_per_pixel (framecnt_t spp)
4295 clamp_samples_per_pixel (spp);
4296 samples_per_pixel = spp;
4299 tempo_lines->tempo_map_changed();
4302 /* convert fpu to frame count */
4304 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4306 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4307 zoom_range_clock->set (frames);
4310 bool const showing_time_selection = selection->time.length() > 0;
4312 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4313 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4314 (*i)->reshow_selection (selection->time);
4318 ZoomChanged (); /* EMIT_SIGNAL */
4320 ArdourCanvas::GtkCanvasViewport* c;
4322 c = get_time_bars_canvas();
4324 c->canvas()->zoomed ();
4326 c = get_track_canvas();
4328 c->canvas()->zoomed ();
4331 if (playhead_cursor) {
4332 playhead_cursor->set_position (playhead_cursor->current_frame ());
4335 refresh_location_display();
4336 _summary->set_overlays_dirty ();
4338 update_marker_labels ();
4344 Editor::queue_visual_videotimeline_update ()
4347 * pending_visual_change.add (VisualChange::VideoTimeline);
4348 * or maybe even more specific: which videotimeline-image
4349 * currently it calls update_video_timeline() to update
4350 * _all outdated_ images on the video-timeline.
4351 * see 'exposeimg()' in video_image_frame.cc
4353 ensure_visual_change_idle_handler ();
4357 Editor::ensure_visual_change_idle_handler ()
4359 if (pending_visual_change.idle_handler_id < 0) {
4360 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4361 pending_visual_change.being_handled = false;
4366 Editor::_idle_visual_changer (void* arg)
4368 return static_cast<Editor*>(arg)->idle_visual_changer ();
4372 Editor::idle_visual_changer ()
4374 /* set_horizontal_position() below (and maybe other calls) call
4375 gtk_main_iteration(), so it's possible that a signal will be handled
4376 half-way through this method. If this signal wants an
4377 idle_visual_changer we must schedule another one after this one, so
4378 mark the idle_handler_id as -1 here to allow that. Also make a note
4379 that we are doing the visual change, so that changes in response to
4380 super-rapid-screen-update can be dropped if we are still processing
4384 pending_visual_change.idle_handler_id = -1;
4385 pending_visual_change.being_handled = true;
4387 VisualChange vc = pending_visual_change;
4389 pending_visual_change.pending = (VisualChange::Type) 0;
4391 visual_changer (vc);
4393 pending_visual_change.being_handled = false;
4395 return 0; /* this is always a one-shot call */
4399 Editor::visual_changer (const VisualChange& vc)
4401 double const last_time_origin = horizontal_position ();
4403 if (vc.pending & VisualChange::ZoomLevel) {
4404 set_samples_per_pixel (vc.samples_per_pixel);
4406 compute_fixed_ruler_scale ();
4408 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4409 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4411 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4412 current_bbt_points_begin, current_bbt_points_end);
4413 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4414 current_bbt_points_begin, current_bbt_points_end);
4415 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4417 update_video_timeline();
4420 if (vc.pending & VisualChange::TimeOrigin) {
4421 set_horizontal_position (vc.time_origin / samples_per_pixel);
4424 if (vc.pending & VisualChange::YOrigin) {
4425 vertical_adjustment.set_value (vc.y_origin);
4428 if (last_time_origin == horizontal_position ()) {
4429 /* changed signal not emitted */
4430 update_fixed_rulers ();
4431 redisplay_tempo (true);
4434 if (!(vc.pending & VisualChange::ZoomLevel)) {
4435 update_video_timeline();
4438 _summary->set_overlays_dirty ();
4441 struct EditorOrderTimeAxisSorter {
4442 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4443 return a->order () < b->order ();
4448 Editor::sort_track_selection (TrackViewList& sel)
4450 EditorOrderTimeAxisSorter cmp;
4455 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4458 framepos_t where = 0;
4459 EditPoint ep = _edit_point;
4461 if (from_context_menu && (ep == EditAtMouse)) {
4462 return canvas_event_sample (&context_click_event, 0, 0);
4465 if (entered_marker) {
4466 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4467 return entered_marker->position();
4470 if (ignore_playhead && ep == EditAtPlayhead) {
4471 ep = EditAtSelectedMarker;
4475 case EditAtPlayhead:
4476 where = _session->audible_frame();
4477 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4480 case EditAtSelectedMarker:
4481 if (!selection->markers.empty()) {
4483 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4486 where = loc->start();
4490 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4498 if (!mouse_frame (where, ignored)) {
4499 /* XXX not right but what can we do ? */
4503 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4511 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4513 if (!_session) return;
4515 begin_reversible_command (cmd);
4519 if ((tll = transport_loop_location()) == 0) {
4520 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4521 XMLNode &before = _session->locations()->get_state();
4522 _session->locations()->add (loc, true);
4523 _session->set_auto_loop_location (loc);
4524 XMLNode &after = _session->locations()->get_state();
4525 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4527 XMLNode &before = tll->get_state();
4528 tll->set_hidden (false, this);
4529 tll->set (start, end);
4530 XMLNode &after = tll->get_state();
4531 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4534 commit_reversible_command ();
4538 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4540 if (!_session) return;
4542 begin_reversible_command (cmd);
4546 if ((tpl = transport_punch_location()) == 0) {
4547 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4548 XMLNode &before = _session->locations()->get_state();
4549 _session->locations()->add (loc, true);
4550 _session->set_auto_punch_location (loc);
4551 XMLNode &after = _session->locations()->get_state();
4552 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4555 XMLNode &before = tpl->get_state();
4556 tpl->set_hidden (false, this);
4557 tpl->set (start, end);
4558 XMLNode &after = tpl->get_state();
4559 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4562 commit_reversible_command ();
4565 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4566 * @param rs List to which found regions are added.
4567 * @param where Time to look at.
4568 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4571 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4573 const TrackViewList* tracks;
4576 tracks = &track_views;
4581 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4583 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4586 boost::shared_ptr<Track> tr;
4587 boost::shared_ptr<Playlist> pl;
4589 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4591 boost::shared_ptr<RegionList> regions = pl->regions_at (
4592 (framepos_t) floor ( (double) where * tr->speed()));
4594 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4595 RegionView* rv = rtv->view()->find_view (*i);
4606 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4608 const TrackViewList* tracks;
4611 tracks = &track_views;
4616 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4619 boost::shared_ptr<Track> tr;
4620 boost::shared_ptr<Playlist> pl;
4622 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4624 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4625 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4627 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4629 RegionView* rv = rtv->view()->find_view (*i);
4640 /** Get regions using the following method:
4642 * Make a region list using the selected regions, unless
4643 * the edit point is `mouse' and the mouse is over an unselected
4644 * region. In this case, use just that region.
4646 * If the edit point is not 'mouse', and there are no regions selected,
4647 * search the list of selected tracks and return regions that are under
4648 * the edit point on these tracks. If there are no selected tracks and
4649 * 'No Selection = All Tracks' is active, search all tracks,
4651 * The rationale here is that the mouse edit point is special in that
4652 * its position describes both a time and a track; the other edit
4653 * modes only describe a time. Hence if the edit point is `mouse' we
4654 * ignore selected tracks, as we assume the user means something by
4655 * pointing at a particular track. Also in this case we take note of
4656 * the region directly under the edit point, as there is always just one
4657 * (rather than possibly several with non-mouse edit points).
4661 Editor::get_regions_from_selection_and_edit_point ()
4663 RegionSelection regions;
4665 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4666 regions.add (entered_regionview);
4668 regions = selection->regions;
4672 if (regions.empty() && _edit_point != EditAtMouse) {
4673 TrackViewList tracks = selection->tracks;
4675 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4676 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4677 * is enabled, so consider all tracks
4679 tracks = track_views;
4682 if (!tracks.empty()) {
4683 /* no region selected or entered, but some selected tracks:
4684 * act on all regions on the selected tracks at the edit point
4686 framepos_t const where = get_preferred_edit_position ();
4687 get_regions_at(regions, where, tracks);
4693 /** Start with regions that are selected, or the entered regionview if none are selected.
4694 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4695 * of the regions that we started with.
4699 Editor::get_regions_from_selection_and_entered ()
4701 RegionSelection regions = selection->regions;
4703 if (regions.empty() && entered_regionview) {
4704 regions.add (entered_regionview);
4711 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4713 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4715 RouteTimeAxisView* tatv;
4717 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4719 boost::shared_ptr<Playlist> pl;
4720 vector<boost::shared_ptr<Region> > results;
4722 boost::shared_ptr<Track> tr;
4724 if ((tr = tatv->track()) == 0) {
4729 if ((pl = (tr->playlist())) != 0) {
4730 if (src_comparison) {
4731 pl->get_source_equivalent_regions (region, results);
4733 pl->get_region_list_equivalent_regions (region, results);
4737 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4738 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4739 regions.push_back (marv);
4748 Editor::show_rhythm_ferret ()
4750 if (rhythm_ferret == 0) {
4751 rhythm_ferret = new RhythmFerret(*this);
4754 rhythm_ferret->set_session (_session);
4755 rhythm_ferret->show ();
4756 rhythm_ferret->present ();
4760 Editor::first_idle ()
4762 MessageDialog* dialog = 0;
4764 if (track_views.size() > 1) {
4765 dialog = new MessageDialog (
4767 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4771 ARDOUR_UI::instance()->flush_pending ();
4774 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4778 // first idle adds route children (automation tracks), so we need to redisplay here
4779 _routes->redisplay ();
4786 Editor::_idle_resize (gpointer arg)
4788 return ((Editor*)arg)->idle_resize ();
4792 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4794 if (resize_idle_id < 0) {
4795 resize_idle_id = g_idle_add (_idle_resize, this);
4796 _pending_resize_amount = 0;
4799 /* make a note of the smallest resulting height, so that we can clamp the
4800 lower limit at TimeAxisView::hSmall */
4802 int32_t min_resulting = INT32_MAX;
4804 _pending_resize_amount += h;
4805 _pending_resize_view = view;
4807 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4809 if (selection->tracks.contains (_pending_resize_view)) {
4810 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4811 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4815 if (min_resulting < 0) {
4820 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4821 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4825 /** Handle pending resizing of tracks */
4827 Editor::idle_resize ()
4829 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4831 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4832 selection->tracks.contains (_pending_resize_view)) {
4834 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4835 if (*i != _pending_resize_view) {
4836 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4841 _pending_resize_amount = 0;
4842 _group_tabs->set_dirty ();
4843 resize_idle_id = -1;
4851 ENSURE_GUI_THREAD (*this, &Editor::located);
4854 playhead_cursor->set_position (_session->audible_frame ());
4855 if (_follow_playhead && !_pending_initial_locate) {
4856 reset_x_origin_to_follow_playhead ();
4860 _pending_locate_request = false;
4861 _pending_initial_locate = false;
4865 Editor::region_view_added (RegionView *)
4867 _summary->set_dirty ();
4871 Editor::region_view_removed ()
4873 _summary->set_dirty ();
4877 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4879 TrackViewList::const_iterator j = track_views.begin ();
4880 while (j != track_views.end()) {
4881 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4882 if (rtv && rtv->route() == r) {
4893 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4897 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4898 TimeAxisView* tv = axis_view_from_route (*i);
4908 Editor::add_routes (RouteList& routes)
4910 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4912 RouteTimeAxisView *rtv;
4913 list<RouteTimeAxisView*> new_views;
4915 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4916 boost::shared_ptr<Route> route = (*x);
4918 if (route->is_auditioner() || route->is_monitor()) {
4922 DataType dt = route->input()->default_type();
4924 if (dt == ARDOUR::DataType::AUDIO) {
4925 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4926 rtv->set_route (route);
4927 } else if (dt == ARDOUR::DataType::MIDI) {
4928 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4929 rtv->set_route (route);
4931 throw unknown_type();
4934 new_views.push_back (rtv);
4935 track_views.push_back (rtv);
4937 rtv->effective_gain_display ();
4939 if (internal_editing()) {
4940 rtv->enter_internal_edit_mode ();
4942 rtv->leave_internal_edit_mode ();
4945 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4946 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4949 if (new_views.size() > 0) {
4950 _routes->routes_added (new_views);
4951 _summary->routes_added (new_views);
4954 if (show_editor_mixer_when_tracks_arrive) {
4955 show_editor_mixer (true);
4958 editor_list_button.set_sensitive (true);
4962 Editor::timeaxisview_deleted (TimeAxisView *tv)
4964 if (_session && _session->deletion_in_progress()) {
4965 /* the situation is under control */
4969 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4971 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4973 _routes->route_removed (tv);
4975 if (tv == entered_track) {
4979 TimeAxisView::Children c = tv->get_child_list ();
4980 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4981 if (entered_track == i->get()) {
4986 /* remove it from the list of track views */
4988 TrackViewList::iterator i;
4990 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4991 i = track_views.erase (i);
4994 /* update whatever the current mixer strip is displaying, if revelant */
4996 boost::shared_ptr<Route> route;
4999 route = rtav->route ();
5002 if (current_mixer_strip && current_mixer_strip->route() == route) {
5004 TimeAxisView* next_tv;
5006 if (track_views.empty()) {
5008 } else if (i == track_views.end()) {
5009 next_tv = track_views.front();
5016 set_selected_mixer_strip (*next_tv);
5018 /* make the editor mixer strip go away setting the
5019 * button to inactive (which also unticks the menu option)
5022 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5028 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5030 if (apply_to_selection) {
5031 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5033 TrackSelection::iterator j = i;
5036 hide_track_in_display (*i, false);
5041 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5043 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5044 // this will hide the mixer strip
5045 set_selected_mixer_strip (*tv);
5048 _routes->hide_track_in_display (*tv);
5053 Editor::sync_track_view_list_and_routes ()
5055 track_views = TrackViewList (_routes->views ());
5057 _summary->set_dirty ();
5058 _group_tabs->set_dirty ();
5060 return false; // do not call again (until needed)
5064 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5066 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5071 /** Find a RouteTimeAxisView by the ID of its route */
5073 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5075 RouteTimeAxisView* v;
5077 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5078 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5079 if(v->route()->id() == id) {
5089 Editor::fit_route_group (RouteGroup *g)
5091 TrackViewList ts = axis_views_from_routes (g->route_list ());
5096 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5098 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5101 _session->cancel_audition ();
5105 if (_session->is_auditioning()) {
5106 _session->cancel_audition ();
5107 if (r == last_audition_region) {
5112 _session->audition_region (r);
5113 last_audition_region = r;
5118 Editor::hide_a_region (boost::shared_ptr<Region> r)
5120 r->set_hidden (true);
5124 Editor::show_a_region (boost::shared_ptr<Region> r)
5126 r->set_hidden (false);
5130 Editor::audition_region_from_region_list ()
5132 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5136 Editor::hide_region_from_region_list ()
5138 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5142 Editor::show_region_in_region_list ()
5144 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5148 Editor::step_edit_status_change (bool yn)
5151 start_step_editing ();
5153 stop_step_editing ();
5158 Editor::start_step_editing ()
5160 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5164 Editor::stop_step_editing ()
5166 step_edit_connection.disconnect ();
5170 Editor::check_step_edit ()
5172 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5173 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5175 mtv->check_step_edit ();
5179 return true; // do it again, till we stop
5183 Editor::scroll_press (Direction dir)
5185 ++_scroll_callbacks;
5187 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5188 /* delay the first auto-repeat */
5194 scroll_backward (1);
5202 scroll_tracks_up_line ();
5206 scroll_tracks_down_line ();
5210 /* do hacky auto-repeat */
5211 if (!_scroll_connection.connected ()) {
5213 _scroll_connection = Glib::signal_timeout().connect (
5214 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5217 _scroll_callbacks = 0;
5224 Editor::scroll_release ()
5226 _scroll_connection.disconnect ();
5229 /** Queue a change for the Editor viewport x origin to follow the playhead */
5231 Editor::reset_x_origin_to_follow_playhead ()
5233 framepos_t const frame = playhead_cursor->current_frame ();
5235 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5237 if (_session->transport_speed() < 0) {
5239 if (frame > (current_page_samples() / 2)) {
5240 center_screen (frame-(current_page_samples()/2));
5242 center_screen (current_page_samples()/2);
5249 if (frame < leftmost_frame) {
5251 if (_session->transport_rolling()) {
5252 /* rolling; end up with the playhead at the right of the page */
5253 l = frame - current_page_samples ();
5255 /* not rolling: end up with the playhead 1/4 of the way along the page */
5256 l = frame - current_page_samples() / 4;
5260 if (_session->transport_rolling()) {
5261 /* rolling: end up with the playhead on the left of the page */
5264 /* not rolling: end up with the playhead 3/4 of the way along the page */
5265 l = frame - 3 * current_page_samples() / 4;
5273 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5279 Editor::super_rapid_screen_update ()
5281 if (!_session || !_session->engine().running()) {
5285 /* METERING / MIXER STRIPS */
5287 /* update track meters, if required */
5288 if (is_mapped() && meters_running) {
5289 RouteTimeAxisView* rtv;
5290 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5291 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5292 rtv->fast_update ();
5297 /* and any current mixer strip */
5298 if (current_mixer_strip) {
5299 current_mixer_strip->fast_update ();
5302 /* PLAYHEAD AND VIEWPORT */
5304 framepos_t const frame = _session->audible_frame();
5306 /* There are a few reasons why we might not update the playhead / viewport stuff:
5308 * 1. we don't update things when there's a pending locate request, otherwise
5309 * when the editor requests a locate there is a chance that this method
5310 * will move the playhead before the locate request is processed, causing
5312 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5313 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5316 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5318 last_update_frame = frame;
5320 if (!_dragging_playhead) {
5321 playhead_cursor->set_position (frame);
5324 if (!_stationary_playhead) {
5326 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5327 /* We only do this if we aren't already
5328 handling a visual change (ie if
5329 pending_visual_change.being_handled is
5330 false) so that these requests don't stack
5331 up there are too many of them to handle in
5334 reset_x_origin_to_follow_playhead ();
5339 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5343 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5344 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5345 if (target <= 0.0) {
5348 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5349 target = (target * 0.15) + (current * 0.85);
5355 set_horizontal_position (current);
5364 Editor::session_going_away ()
5366 _have_idled = false;
5368 _session_connections.drop_connections ();
5370 super_rapid_screen_update_connection.disconnect ();
5372 selection->clear ();
5373 cut_buffer->clear ();
5375 clicked_regionview = 0;
5376 clicked_axisview = 0;
5377 clicked_routeview = 0;
5378 entered_regionview = 0;
5380 last_update_frame = 0;
5383 playhead_cursor->hide ();
5385 /* rip everything out of the list displays */
5389 _route_groups->clear ();
5391 /* do this first so that deleting a track doesn't reset cms to null
5392 and thus cause a leak.
5395 if (current_mixer_strip) {
5396 if (current_mixer_strip->get_parent() != 0) {
5397 global_hpacker.remove (*current_mixer_strip);
5399 delete current_mixer_strip;
5400 current_mixer_strip = 0;
5403 /* delete all trackviews */
5405 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5408 track_views.clear ();
5410 zoom_range_clock->set_session (0);
5411 nudge_clock->set_session (0);
5413 editor_list_button.set_active(false);
5414 editor_list_button.set_sensitive(false);
5416 /* clear tempo/meter rulers */
5417 remove_metric_marks ();
5419 clear_marker_display ();
5421 stop_step_editing ();
5423 /* get rid of any existing editor mixer strip */
5425 WindowTitle title(Glib::get_application_name());
5426 title += _("Editor");
5428 set_title (title.get_string());
5430 SessionHandlePtr::session_going_away ();
5435 Editor::show_editor_list (bool yn)
5438 _the_notebook.show ();
5440 _the_notebook.hide ();
5445 Editor::change_region_layering_order (bool from_context_menu)
5447 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5449 if (!clicked_routeview) {
5450 if (layering_order_editor) {
5451 layering_order_editor->hide ();
5456 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5462 boost::shared_ptr<Playlist> pl = track->playlist();
5468 if (layering_order_editor == 0) {
5469 layering_order_editor = new RegionLayeringOrderEditor (*this);
5472 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5473 layering_order_editor->maybe_present ();
5477 Editor::update_region_layering_order_editor ()
5479 if (layering_order_editor && layering_order_editor->is_visible ()) {
5480 change_region_layering_order (true);
5485 Editor::setup_fade_images ()
5487 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5488 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5489 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5490 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5491 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5493 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5494 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5495 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5496 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5497 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5499 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5500 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5501 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5502 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5503 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5505 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5506 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5507 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5508 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5509 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5513 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5515 Editor::action_menu_item (std::string const & name)
5517 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5520 return *manage (a->create_menu_item ());
5524 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5526 EventBox* b = manage (new EventBox);
5527 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5528 Label* l = manage (new Label (name));
5532 _the_notebook.append_page (widget, *b);
5536 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5538 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5539 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5542 if (ev->type == GDK_2BUTTON_PRESS) {
5544 /* double-click on a notebook tab shrinks or expands the notebook */
5546 if (_notebook_shrunk) {
5547 if (pre_notebook_shrink_pane_width) {
5548 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5550 _notebook_shrunk = false;
5552 pre_notebook_shrink_pane_width = edit_pane.get_position();
5554 /* this expands the LHS of the edit pane to cover the notebook
5555 PAGE but leaves the tabs visible.
5557 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5558 _notebook_shrunk = true;
5566 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5568 using namespace Menu_Helpers;
5570 MenuList& items = _control_point_context_menu.items ();
5573 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5574 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5575 if (!can_remove_control_point (item)) {
5576 items.back().set_sensitive (false);
5579 _control_point_context_menu.popup (event->button.button, event->button.time);
5583 Editor::zoom_vertical_modifier_released()
5585 _stepping_axis_view = 0;