2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 #ifdef WITH_VIDEOTIMELINE
250 , videotl_label (_("Video Timeline"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 /* tool bar related */
262 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
264 , toolbar_selection_clock_table (2,3)
266 , automation_mode_button (_("mode"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , image_socket_listener(0)
276 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
283 , _following_mixer_selection (false)
284 , _control_point_toggled_on_press (false)
285 , _stepping_axis_view (0)
289 /* we are a singleton */
291 PublicEditor::_instance = this;
295 selection = new Selection (this);
296 cut_buffer = new Selection (this);
298 clicked_regionview = 0;
299 clicked_axisview = 0;
300 clicked_routeview = 0;
301 clicked_control_point = 0;
302 last_update_frame = 0;
303 pre_press_cursor = 0;
304 _drags = new DragManager (this);
305 current_mixer_strip = 0;
308 snap_type_strings = I18N (_snap_type_strings);
309 snap_mode_strings = I18N (_snap_mode_strings);
310 zoom_focus_strings = I18N (_zoom_focus_strings);
311 edit_point_strings = I18N (_edit_point_strings);
312 #ifdef USE_RUBBERBAND
313 rb_opt_strings = I18N (_rb_opt_strings);
317 snap_threshold = 5.0;
318 bbt_beat_subdivision = 4;
319 _visible_canvas_width = 0;
320 _visible_canvas_height = 0;
321 last_autoscroll_x = 0;
322 last_autoscroll_y = 0;
323 autoscroll_active = false;
324 autoscroll_timeout_tag = -1;
329 current_interthread_info = 0;
330 _show_measures = true;
332 show_gain_after_trim = false;
334 have_pending_keyboard_selection = false;
335 _follow_playhead = true;
336 _stationary_playhead = false;
337 editor_ruler_menu = 0;
338 no_ruler_shown_update = false;
340 range_marker_menu = 0;
341 marker_menu_item = 0;
342 tempo_or_meter_marker_menu = 0;
343 transport_marker_menu = 0;
344 new_transport_marker_menu = 0;
345 editor_mixer_strip_width = Wide;
346 show_editor_mixer_when_tracks_arrive = false;
347 region_edit_menu_split_multichannel_item = 0;
348 region_edit_menu_split_item = 0;
351 current_stepping_trackview = 0;
353 entered_regionview = 0;
355 clear_entered_track = false;
358 button_release_can_deselect = true;
359 _dragging_playhead = false;
360 _dragging_edit_point = false;
361 select_new_marker = false;
363 layering_order_editor = 0;
364 no_save_visual = false;
366 within_track_canvas = false;
368 scrubbing_direction = 0;
372 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
373 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
374 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
375 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
376 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
378 _edit_point = EditAtMouse;
379 _internal_editing = false;
380 current_canvas_cursor = 0;
382 frames_per_pixel = 2048; /* too early to use reset_zoom () */
384 _scroll_callbacks = 0;
386 zoom_focus = ZoomFocusLeft;
387 set_zoom_focus (ZoomFocusLeft);
388 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
390 bbt_label.set_name ("EditorRulerLabel");
391 bbt_label.set_size_request (-1, (int)timebar_height);
392 bbt_label.set_alignment (1.0, 0.5);
393 bbt_label.set_padding (5,0);
395 bbt_label.set_no_show_all();
396 minsec_label.set_name ("EditorRulerLabel");
397 minsec_label.set_size_request (-1, (int)timebar_height);
398 minsec_label.set_alignment (1.0, 0.5);
399 minsec_label.set_padding (5,0);
400 minsec_label.hide ();
401 minsec_label.set_no_show_all();
402 timecode_label.set_name ("EditorRulerLabel");
403 timecode_label.set_size_request (-1, (int)timebar_height);
404 timecode_label.set_alignment (1.0, 0.5);
405 timecode_label.set_padding (5,0);
406 timecode_label.hide ();
407 timecode_label.set_no_show_all();
408 samples_label.set_name ("EditorRulerLabel");
409 samples_label.set_size_request (-1, (int)timebar_height);
410 samples_label.set_alignment (1.0, 0.5);
411 samples_label.set_padding (5,0);
412 samples_label.hide ();
413 samples_label.set_no_show_all();
415 tempo_label.set_name ("EditorRulerLabel");
416 tempo_label.set_size_request (-1, (int)timebar_height);
417 tempo_label.set_alignment (1.0, 0.5);
418 tempo_label.set_padding (5,0);
420 tempo_label.set_no_show_all();
422 meter_label.set_name ("EditorRulerLabel");
423 meter_label.set_size_request (-1, (int)timebar_height);
424 meter_label.set_alignment (1.0, 0.5);
425 meter_label.set_padding (5,0);
427 meter_label.set_no_show_all();
429 mark_label.set_name ("EditorRulerLabel");
430 mark_label.set_size_request (-1, (int)timebar_height);
431 mark_label.set_alignment (1.0, 0.5);
432 mark_label.set_padding (5,0);
434 mark_label.set_no_show_all();
436 cd_mark_label.set_name ("EditorRulerLabel");
437 cd_mark_label.set_size_request (-1, (int)timebar_height);
438 cd_mark_label.set_alignment (1.0, 0.5);
439 cd_mark_label.set_padding (5,0);
440 cd_mark_label.hide();
441 cd_mark_label.set_no_show_all();
443 #ifdef WITH_VIDEOTIMELINE
444 videotl_bar_height = 4;
445 videotl_label.set_name ("EditorRulerLabel");
446 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
447 videotl_label.set_alignment (1.0, 0.5);
448 videotl_label.set_padding (5,0);
449 videotl_label.hide();
450 videotl_label.set_no_show_all();
453 range_mark_label.set_name ("EditorRulerLabel");
454 range_mark_label.set_size_request (-1, (int)timebar_height);
455 range_mark_label.set_alignment (1.0, 0.5);
456 range_mark_label.set_padding (5,0);
457 range_mark_label.hide();
458 range_mark_label.set_no_show_all();
460 transport_mark_label.set_name ("EditorRulerLabel");
461 transport_mark_label.set_size_request (-1, (int)timebar_height);
462 transport_mark_label.set_alignment (1.0, 0.5);
463 transport_mark_label.set_padding (5,0);
464 transport_mark_label.hide();
465 transport_mark_label.set_no_show_all();
467 initialize_rulers ();
468 initialize_canvas ();
470 _summary = new EditorSummary (this);
472 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
473 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
475 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
477 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
478 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
480 edit_controls_vbox.set_spacing (0);
481 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
482 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
484 HBox* h = manage (new HBox);
485 _group_tabs = new EditorGroupTabs (this);
486 h->pack_start (*_group_tabs, PACK_SHRINK);
487 h->pack_start (edit_controls_vbox);
488 controls_layout.add (*h);
490 controls_layout.set_name ("EditControlsBase");
491 controls_layout.add_events (Gdk::SCROLL_MASK);
492 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
494 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
495 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
497 _cursors = new MouseCursors;
499 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::GtkCanvas());
500 ArdourCanvas::Line* pad_line_1 = manage(new ArdourCanvas::Line(time_pad->root()));
501 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
503 pad_line_1->set_outline_color (0xFF0000FF);
508 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
509 time_canvas_vbox.set_size_request (-1, -1);
511 ruler_label_event_box.add (ruler_label_vbox);
512 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
513 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
515 time_bars_event_box.add (time_bars_vbox);
516 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
517 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
519 /* these enable us to have a dedicated window (for cursor setting, etc.)
520 for the canvas areas.
523 track_canvas_event_box.add (*_track_canvas_viewport);
525 time_canvas_event_box.add (time_canvas_vbox);
526 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
528 edit_packer.set_col_spacings (0);
529 edit_packer.set_row_spacings (0);
530 edit_packer.set_homogeneous (false);
531 edit_packer.set_border_width (0);
532 edit_packer.set_name ("EditorWindow");
534 /* labels for the rulers */
535 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
536 /* labels for the marker "tracks" (time bars) */
537 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
539 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
541 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
542 /* time bars canvas */
543 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
545 edit_packer.attach (track_canvas_event_box, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
547 bottom_hbox.set_border_width (2);
548 bottom_hbox.set_spacing (3);
550 _route_groups = new EditorRouteGroups (this);
551 _routes = new EditorRoutes (this);
552 _regions = new EditorRegions (this);
553 _snapshots = new EditorSnapshots (this);
554 _locations = new EditorLocations (this);
556 add_notebook_page (_("Regions"), _regions->widget ());
557 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
558 add_notebook_page (_("Snapshots"), _snapshots->widget ());
559 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
560 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
562 _the_notebook.set_show_tabs (true);
563 _the_notebook.set_scrollable (true);
564 _the_notebook.popup_disable ();
565 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
566 _the_notebook.show_all ();
568 _notebook_shrunk = false;
570 editor_summary_pane.pack1(edit_packer);
572 Button* summary_arrows_left_left = manage (new Button);
573 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
574 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
575 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_left_right = manage (new Button);
578 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
579 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
580 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_left = manage (new VBox);
583 summary_arrows_left->pack_start (*summary_arrows_left_left);
584 summary_arrows_left->pack_start (*summary_arrows_left_right);
586 Button* summary_arrows_right_up = manage (new Button);
587 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
588 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
589 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 Button* summary_arrows_right_down = manage (new Button);
592 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
593 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
594 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
596 VBox* summary_arrows_right = manage (new VBox);
597 summary_arrows_right->pack_start (*summary_arrows_right_up);
598 summary_arrows_right->pack_start (*summary_arrows_right_down);
600 Frame* summary_frame = manage (new Frame);
601 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
603 summary_frame->add (*_summary);
604 summary_frame->show ();
606 _summary_hbox.pack_start (*summary_arrows_left, false, false);
607 _summary_hbox.pack_start (*summary_frame, true, true);
608 _summary_hbox.pack_start (*summary_arrows_right, false, false);
610 editor_summary_pane.pack2 (_summary_hbox);
612 edit_pane.pack1 (editor_summary_pane, true, true);
613 edit_pane.pack2 (_the_notebook, false, true);
615 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
617 /* XXX: editor_summary_pane might need similar to the edit_pane */
619 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
621 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
622 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
624 top_hbox.pack_start (toolbar_frame);
626 HBox *hbox = manage (new HBox);
627 hbox->pack_start (edit_pane, true, true);
629 global_vpacker.pack_start (top_hbox, false, false);
630 global_vpacker.pack_start (*hbox, true, true);
632 global_hpacker.pack_start (global_vpacker, true, true);
634 set_name ("EditorWindow");
635 add_accel_group (ActionManager::ui_manager->get_accel_group());
637 status_bar_hpacker.show ();
639 vpacker.pack_end (status_bar_hpacker, false, false);
640 vpacker.pack_end (global_hpacker, true, true);
642 /* register actions now so that set_state() can find them and set toggles/checks etc */
645 /* when we start using our own keybinding system for the editor, this
646 * will be uncommented
652 _snap_type = SnapToBeat;
653 set_snap_to (_snap_type);
654 _snap_mode = SnapOff;
655 set_snap_mode (_snap_mode);
656 set_mouse_mode (MouseObject, true);
657 pre_internal_mouse_mode = MouseObject;
658 pre_internal_snap_type = _snap_type;
659 pre_internal_snap_mode = _snap_mode;
660 internal_snap_type = _snap_type;
661 internal_snap_mode = _snap_mode;
662 set_edit_point_preference (EditAtMouse, true);
664 _playlist_selector = new PlaylistSelector();
665 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
667 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
671 nudge_forward_button.set_name ("zoom button");
672 nudge_forward_button.add_elements (ArdourButton::FlatFace);
673 nudge_forward_button.set_image(::get_icon("nudge_right"));
675 nudge_backward_button.set_name ("zoom button");
676 nudge_backward_button.add_elements (ArdourButton::FlatFace);
677 nudge_backward_button.set_image(::get_icon("nudge_left"));
679 fade_context_menu.set_name ("ArdourContextMenu");
681 /* icons, titles, WM stuff */
683 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
684 Glib::RefPtr<Gdk::Pixbuf> icon;
686 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
687 window_icons.push_back (icon);
689 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
690 window_icons.push_back (icon);
692 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
693 window_icons.push_back (icon);
695 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
696 window_icons.push_back (icon);
698 if (!window_icons.empty()) {
699 // set_icon_list (window_icons);
700 set_default_icon_list (window_icons);
703 WindowTitle title(Glib::get_application_name());
704 title += _("Editor");
705 set_title (title.get_string());
706 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
709 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
711 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
712 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
714 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
716 /* allow external control surfaces/protocols to do various things */
718 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
719 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
720 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
721 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
722 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
723 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
724 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
725 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
726 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
727 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
728 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
729 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
730 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
731 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
733 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
734 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
735 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
736 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
737 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
739 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
741 /* problematic: has to return a value and thus cannot be x-thread */
743 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
745 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
747 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
749 _ignore_region_action = false;
750 _last_region_menu_was_main = false;
751 _popup_region_menu_item = 0;
753 _show_marker_lines = false;
754 _over_region_trim_target = false;
756 /* Button bindings */
758 button_bindings = new Bindings;
760 XMLNode* node = button_settings();
762 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
763 button_bindings->load (**i);
770 setup_fade_images ();
776 if(image_socket_listener) {
777 if(image_socket_listener->is_connected())
779 image_socket_listener->close_connection() ;
782 delete image_socket_listener ;
783 image_socket_listener = 0 ;
787 delete button_bindings;
789 delete _route_groups;
790 delete _track_canvas_viewport;
795 Editor::button_settings () const
797 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
798 XMLNode* node = find_named_node (*settings, X_("Buttons"));
801 node = new XMLNode (X_("Buttons"));
808 Editor::add_toplevel_controls (Container& cont)
810 vpacker.pack_start (cont, false, false);
815 Editor::get_smart_mode () const
817 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
821 Editor::catch_vanishing_regionview (RegionView *rv)
823 /* note: the selection will take care of the vanishing
824 audioregionview by itself.
827 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
831 if (clicked_regionview == rv) {
832 clicked_regionview = 0;
835 if (entered_regionview == rv) {
836 set_entered_regionview (0);
839 if (!_all_region_actions_sensitized) {
840 sensitize_all_region_actions (true);
843 _over_region_trim_target = false;
847 Editor::set_entered_regionview (RegionView* rv)
849 if (rv == entered_regionview) {
853 if (entered_regionview) {
854 entered_regionview->exited ();
857 if ((entered_regionview = rv) != 0) {
858 entered_regionview->entered (internal_editing ());
861 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
862 /* This RegionView entry might have changed what region actions
863 are allowed, so sensitize them all in case a key is pressed.
865 sensitize_all_region_actions (true);
870 Editor::set_entered_track (TimeAxisView* tav)
873 entered_track->exited ();
876 if ((entered_track = tav) != 0) {
877 entered_track->entered ();
882 Editor::show_window ()
884 if (!is_visible ()) {
887 /* XXX: this is a bit unfortunate; it would probably
888 be nicer if we could just call show () above rather
889 than needing the show_all ()
892 /* re-hide stuff if necessary */
893 editor_list_button_toggled ();
894 parameter_changed ("show-summary");
895 parameter_changed ("show-group-tabs");
896 parameter_changed ("show-zoom-tools");
898 /* now reset all audio_time_axis heights, because widgets might need
904 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
905 tv = (static_cast<TimeAxisView*>(*i));
909 if (current_mixer_strip) {
910 current_mixer_strip->hide_things ();
911 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
919 Editor::instant_save ()
921 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
926 _session->add_instant_xml(get_state());
928 Config->add_instant_xml(get_state());
933 Editor::zoom_adjustment_changed ()
939 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
940 bool clamped = clamp_frames_per_pixel (fpu);
943 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
950 Editor::control_vertical_zoom_in_all ()
952 tav_zoom_smooth (false, true);
956 Editor::control_vertical_zoom_out_all ()
958 tav_zoom_smooth (true, true);
962 Editor::control_vertical_zoom_in_selected ()
964 tav_zoom_smooth (false, false);
968 Editor::control_vertical_zoom_out_selected ()
970 tav_zoom_smooth (true, false);
974 Editor::control_view (uint32_t view)
976 goto_visual_state (view);
980 Editor::control_unselect ()
982 selection->clear_tracks ();
986 Editor::control_select (uint32_t rid, Selection::Operation op)
988 /* handles the (static) signal from the ControlProtocol class that
989 * requests setting the selected track to a given RID
996 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1002 TimeAxisView* tav = axis_view_from_route (r);
1006 case Selection::Add:
1007 selection->add (tav);
1009 case Selection::Toggle:
1010 selection->toggle (tav);
1012 case Selection::Extend:
1014 case Selection::Set:
1015 selection->set (tav);
1019 selection->clear_tracks ();
1024 Editor::control_step_tracks_up ()
1026 scroll_tracks_up_line ();
1030 Editor::control_step_tracks_down ()
1032 scroll_tracks_down_line ();
1036 Editor::control_scroll (float fraction)
1038 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1044 double step = fraction * current_page_frames();
1047 _control_scroll_target is an optional<T>
1049 it acts like a pointer to an framepos_t, with
1050 a operator conversion to boolean to check
1051 that it has a value could possibly use
1052 playhead_cursor->current_frame to store the
1053 value and a boolean in the class to know
1054 when it's out of date
1057 if (!_control_scroll_target) {
1058 _control_scroll_target = _session->transport_frame();
1059 _dragging_playhead = true;
1062 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1063 *_control_scroll_target = 0;
1064 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1065 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1067 *_control_scroll_target += (framepos_t) floor (step);
1070 /* move visuals, we'll catch up with it later */
1072 playhead_cursor->set_position (*_control_scroll_target);
1073 UpdateAllTransportClocks (*_control_scroll_target);
1075 if (*_control_scroll_target > (current_page_frames() / 2)) {
1076 /* try to center PH in window */
1077 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1083 Now we do a timeout to actually bring the session to the right place
1084 according to the playhead. This is to avoid reading disk buffers on every
1085 call to control_scroll, which is driven by ScrollTimeline and therefore
1086 probably by a control surface wheel which can generate lots of events.
1088 /* cancel the existing timeout */
1090 control_scroll_connection.disconnect ();
1092 /* add the next timeout */
1094 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1098 Editor::deferred_control_scroll (framepos_t /*target*/)
1100 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1101 // reset for next stream
1102 _control_scroll_target = boost::none;
1103 _dragging_playhead = false;
1108 Editor::access_action (std::string action_group, std::string action_item)
1114 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1117 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1125 Editor::on_realize ()
1127 Window::on_realize ();
1132 Editor::map_position_change (framepos_t frame)
1134 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1136 if (_session == 0) {
1140 if (_follow_playhead) {
1141 center_screen (frame);
1144 playhead_cursor->set_position (frame);
1148 Editor::center_screen (framepos_t frame)
1150 double const page = _visible_canvas_width * frames_per_pixel;
1152 /* if we're off the page, then scroll.
1155 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1156 center_screen_internal (frame, page);
1161 Editor::center_screen_internal (framepos_t frame, float page)
1166 frame -= (framepos_t) page;
1171 reset_x_origin (frame);
1176 Editor::update_title ()
1178 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1181 bool dirty = _session->dirty();
1183 string session_name;
1185 if (_session->snap_name() != _session->name()) {
1186 session_name = _session->snap_name();
1188 session_name = _session->name();
1192 session_name = "*" + session_name;
1195 WindowTitle title(session_name);
1196 title += Glib::get_application_name();
1197 set_title (title.get_string());
1199 /* ::session_going_away() will have taken care of it */
1204 Editor::set_session (Session *t)
1206 SessionHandlePtr::set_session (t);
1212 zoom_range_clock->set_session (_session);
1213 _playlist_selector->set_session (_session);
1214 nudge_clock->set_session (_session);
1215 _summary->set_session (_session);
1216 _group_tabs->set_session (_session);
1217 _route_groups->set_session (_session);
1218 _regions->set_session (_session);
1219 _snapshots->set_session (_session);
1220 _routes->set_session (_session);
1221 _locations->set_session (_session);
1223 if (rhythm_ferret) {
1224 rhythm_ferret->set_session (_session);
1227 if (analysis_window) {
1228 analysis_window->set_session (_session);
1232 sfbrowser->set_session (_session);
1235 compute_fixed_ruler_scale ();
1237 /* Make sure we have auto loop and auto punch ranges */
1239 Location* loc = _session->locations()->auto_loop_location();
1241 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1243 if (loc->start() == loc->end()) {
1244 loc->set_end (loc->start() + 1);
1247 _session->locations()->add (loc, false);
1248 _session->set_auto_loop_location (loc);
1251 loc->set_name (_("Loop"));
1254 loc = _session->locations()->auto_punch_location();
1257 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1259 if (loc->start() == loc->end()) {
1260 loc->set_end (loc->start() + 1);
1263 _session->locations()->add (loc, false);
1264 _session->set_auto_punch_location (loc);
1267 loc->set_name (_("Punch"));
1270 refresh_location_display ();
1272 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1273 the selected Marker; this needs the LocationMarker list to be available.
1275 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1276 set_state (*node, Stateful::loading_state_version);
1278 /* catch up with the playhead */
1280 _session->request_locate (playhead_cursor->current_frame ());
1281 _pending_initial_locate = true;
1285 /* These signals can all be emitted by a non-GUI thread. Therefore the
1286 handlers for them must not attempt to directly interact with the GUI,
1287 but use Gtkmm2ext::UI::instance()->call_slot();
1290 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1291 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1292 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1293 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1294 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1295 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1296 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1297 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1298 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1299 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1300 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1301 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1302 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1303 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1305 playhead_cursor->show ();
1307 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1308 Config->map_parameters (pc);
1309 _session->config.map_parameters (pc);
1311 restore_ruler_visibility ();
1312 //tempo_map_changed (PropertyChange (0));
1313 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1315 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1316 (static_cast<TimeAxisView*>(*i))->set_frames_per_pixel (frames_per_pixel);
1319 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1320 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1323 switch (_snap_type) {
1324 case SnapToRegionStart:
1325 case SnapToRegionEnd:
1326 case SnapToRegionSync:
1327 case SnapToRegionBoundary:
1328 build_region_boundary_cache ();
1335 /* register for undo history */
1336 _session->register_with_memento_command_factory(id(), this);
1338 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1340 start_updating_meters ();
1344 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1346 if (a->get_name() == "RegionMenu") {
1347 /* When the main menu's region menu is opened, we setup the actions so that they look right
1348 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1349 so we resensitize all region actions when the entered regionview or the region selection
1350 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1351 happens after the region context menu is opened. So we set a flag here, too.
1355 sensitize_the_right_region_actions ();
1356 _last_region_menu_was_main = true;
1361 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1363 using namespace Menu_Helpers;
1365 void (Editor::*emf)(FadeShape);
1366 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1369 images = &_xfade_in_images;
1370 emf = &Editor::set_fade_in_shape;
1372 images = &_xfade_out_images;
1373 emf = &Editor::set_fade_out_shape;
1378 _("Linear (for highly correlated material)"),
1379 *(*images)[FadeLinear],
1380 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1384 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1388 _("Constant power"),
1389 *(*images)[FadeConstantPower],
1390 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1393 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1398 *(*images)[FadeSymmetric],
1399 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1403 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 *(*images)[FadeSlow],
1409 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1412 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1417 *(*images)[FadeFast],
1418 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1421 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1424 /** Pop up a context menu for when the user clicks on a start crossfade */
1426 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1428 using namespace Menu_Helpers;
1430 MenuList& items (xfade_in_context_menu.items());
1432 if (items.empty()) {
1433 fill_xfade_menu (items, true);
1436 xfade_in_context_menu.popup (button, time);
1439 /** Pop up a context menu for when the user clicks on an end crossfade */
1441 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1443 using namespace Menu_Helpers;
1445 MenuList& items (xfade_out_context_menu.items());
1447 if (items.empty()) {
1448 fill_xfade_menu (items, false);
1451 xfade_out_context_menu.popup (button, time);
1455 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1457 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1459 using namespace Menu_Helpers;
1460 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1463 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1467 MenuList& items (fade_context_menu.items());
1470 switch (item_type) {
1472 case FadeInHandleItem:
1473 if (arv->audio_region()->fade_in_active()) {
1474 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1476 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1479 items.push_back (SeparatorElem());
1481 if (Profile->get_sae()) {
1483 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1484 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1491 *_fade_in_images[FadeLinear],
1492 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *_fade_in_images[FadeSlow],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *_fade_in_images[FadeFast],
1511 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 *_fade_in_images[FadeSymmetric],
1520 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1525 _("Constant power"),
1526 *_fade_in_images[FadeConstantPower],
1527 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1530 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1536 case FadeOutHandleItem:
1537 if (arv->audio_region()->fade_out_active()) {
1538 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1540 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1543 items.push_back (SeparatorElem());
1545 if (Profile->get_sae()) {
1546 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1547 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1553 *_fade_out_images[FadeLinear],
1554 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1558 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1563 *_fade_out_images[FadeSlow],
1564 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1567 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1572 *_fade_out_images[FadeFast],
1573 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1576 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1581 *_fade_out_images[FadeSymmetric],
1582 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1587 _("Constant power"),
1588 *_fade_out_images[FadeConstantPower],
1589 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1592 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1598 fatal << _("programming error: ")
1599 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1604 fade_context_menu.popup (button, time);
1608 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1610 using namespace Menu_Helpers;
1611 Menu* (Editor::*build_menu_function)();
1614 switch (item_type) {
1616 case RegionViewName:
1617 case RegionViewNameHighlight:
1618 case LeftFrameHandle:
1619 case RightFrameHandle:
1620 if (with_selection) {
1621 build_menu_function = &Editor::build_track_selection_context_menu;
1623 build_menu_function = &Editor::build_track_region_context_menu;
1628 if (with_selection) {
1629 build_menu_function = &Editor::build_track_selection_context_menu;
1631 build_menu_function = &Editor::build_track_context_menu;
1636 if (clicked_routeview->track()) {
1637 build_menu_function = &Editor::build_track_context_menu;
1639 build_menu_function = &Editor::build_track_bus_context_menu;
1644 /* probably shouldn't happen but if it does, we don't care */
1648 menu = (this->*build_menu_function)();
1649 menu->set_name ("ArdourContextMenu");
1651 /* now handle specific situations */
1653 switch (item_type) {
1655 case RegionViewName:
1656 case RegionViewNameHighlight:
1657 case LeftFrameHandle:
1658 case RightFrameHandle:
1659 if (!with_selection) {
1660 if (region_edit_menu_split_item) {
1661 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1662 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1664 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1667 if (region_edit_menu_split_multichannel_item) {
1668 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1669 region_edit_menu_split_multichannel_item->set_sensitive (true);
1671 region_edit_menu_split_multichannel_item->set_sensitive (false);
1684 /* probably shouldn't happen but if it does, we don't care */
1688 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1690 /* Bounce to disk */
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = menu->items();
1695 edit_items.push_back (SeparatorElem());
1697 switch (clicked_routeview->audio_track()->freeze_state()) {
1698 case AudioTrack::NoFreeze:
1699 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1702 case AudioTrack::Frozen:
1703 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1706 case AudioTrack::UnFrozen:
1707 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1713 if (item_type == StreamItem && clicked_routeview) {
1714 clicked_routeview->build_underlay_menu(menu);
1717 /* When the region menu is opened, we setup the actions so that they look right
1720 sensitize_the_right_region_actions ();
1721 _last_region_menu_was_main = false;
1723 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1724 menu->popup (button, time);
1728 Editor::build_track_context_menu ()
1730 using namespace Menu_Helpers;
1732 MenuList& edit_items = track_context_menu.items();
1735 add_dstream_context_items (edit_items);
1736 return &track_context_menu;
1740 Editor::build_track_bus_context_menu ()
1742 using namespace Menu_Helpers;
1744 MenuList& edit_items = track_context_menu.items();
1747 add_bus_context_items (edit_items);
1748 return &track_context_menu;
1752 Editor::build_track_region_context_menu ()
1754 using namespace Menu_Helpers;
1755 MenuList& edit_items = track_region_context_menu.items();
1758 /* we've just cleared the track region context menu, so the menu that these
1759 two items were on will have disappeared; stop them dangling.
1761 region_edit_menu_split_item = 0;
1762 region_edit_menu_split_multichannel_item = 0;
1764 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1767 boost::shared_ptr<Track> tr;
1768 boost::shared_ptr<Playlist> pl;
1770 if ((tr = rtv->track())) {
1771 add_region_context_items (edit_items, tr);
1775 add_dstream_context_items (edit_items);
1777 return &track_region_context_menu;
1781 Editor::analyze_region_selection ()
1783 if (analysis_window == 0) {
1784 analysis_window = new AnalysisWindow();
1787 analysis_window->set_session(_session);
1789 analysis_window->show_all();
1792 analysis_window->set_regionmode();
1793 analysis_window->analyze();
1795 analysis_window->present();
1799 Editor::analyze_range_selection()
1801 if (analysis_window == 0) {
1802 analysis_window = new AnalysisWindow();
1805 analysis_window->set_session(_session);
1807 analysis_window->show_all();
1810 analysis_window->set_rangemode();
1811 analysis_window->analyze();
1813 analysis_window->present();
1817 Editor::build_track_selection_context_menu ()
1819 using namespace Menu_Helpers;
1820 MenuList& edit_items = track_selection_context_menu.items();
1821 edit_items.clear ();
1823 add_selection_context_items (edit_items);
1824 // edit_items.push_back (SeparatorElem());
1825 // add_dstream_context_items (edit_items);
1827 return &track_selection_context_menu;
1831 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1833 using namespace Menu_Helpers;
1835 /* OK, stick the region submenu at the top of the list, and then add
1839 RegionSelection rs = get_regions_from_selection_and_entered ();
1841 string::size_type pos = 0;
1842 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1844 /* we have to hack up the region name because "_" has a special
1845 meaning for menu titles.
1848 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1849 menu_item_name.replace (pos, 1, "__");
1853 if (_popup_region_menu_item == 0) {
1854 _popup_region_menu_item = new MenuItem (menu_item_name);
1855 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1856 _popup_region_menu_item->show ();
1858 _popup_region_menu_item->set_label (menu_item_name);
1861 const framepos_t position = get_preferred_edit_position (false, true);
1863 edit_items.push_back (*_popup_region_menu_item);
1864 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1865 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1867 edit_items.push_back (SeparatorElem());
1870 /** Add context menu items relevant to selection ranges.
1871 * @param edit_items List to add the items to.
1874 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1876 using namespace Menu_Helpers;
1878 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1879 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1884 edit_items.push_back (SeparatorElem());
1886 edit_items.push_back (
1888 _("Move Range Start to Previous Region Boundary"),
1889 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1893 edit_items.push_back (
1895 _("Move Range Start to Next Region Boundary"),
1896 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1900 edit_items.push_back (
1902 _("Move Range End to Previous Region Boundary"),
1903 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1907 edit_items.push_back (
1909 _("Move Range End to Next Region Boundary"),
1910 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1914 edit_items.push_back (SeparatorElem());
1915 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1916 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1918 edit_items.push_back (SeparatorElem());
1919 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1921 edit_items.push_back (SeparatorElem());
1922 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1923 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1925 edit_items.push_back (SeparatorElem());
1926 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1928 edit_items.push_back (SeparatorElem());
1929 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1930 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1931 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1933 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1935 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1936 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1937 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1938 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1943 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1945 using namespace Menu_Helpers;
1949 Menu *play_menu = manage (new Menu);
1950 MenuList& play_items = play_menu->items();
1951 play_menu->set_name ("ArdourContextMenu");
1953 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1954 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1955 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1956 play_items.push_back (SeparatorElem());
1957 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1959 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1963 Menu *select_menu = manage (new Menu);
1964 MenuList& select_items = select_menu->items();
1965 select_menu->set_name ("ArdourContextMenu");
1967 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1968 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1969 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1970 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1971 select_items.push_back (SeparatorElem());
1972 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1973 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1974 select_items.push_back (SeparatorElem());
1975 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1976 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1977 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1978 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1979 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1980 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1981 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1983 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1987 Menu *cutnpaste_menu = manage (new Menu);
1988 MenuList& cutnpaste_items = cutnpaste_menu->items();
1989 cutnpaste_menu->set_name ("ArdourContextMenu");
1991 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1992 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1993 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1995 cutnpaste_items.push_back (SeparatorElem());
1997 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1998 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2000 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2002 /* Adding new material */
2004 edit_items.push_back (SeparatorElem());
2005 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2006 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2010 Menu *nudge_menu = manage (new Menu());
2011 MenuList& nudge_items = nudge_menu->items();
2012 nudge_menu->set_name ("ArdourContextMenu");
2014 edit_items.push_back (SeparatorElem());
2015 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2016 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2018 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2020 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2024 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2026 using namespace Menu_Helpers;
2030 Menu *play_menu = manage (new Menu);
2031 MenuList& play_items = play_menu->items();
2032 play_menu->set_name ("ArdourContextMenu");
2034 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2035 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2036 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2040 Menu *select_menu = manage (new Menu);
2041 MenuList& select_items = select_menu->items();
2042 select_menu->set_name ("ArdourContextMenu");
2044 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2045 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2047 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2048 select_items.push_back (SeparatorElem());
2049 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2050 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2051 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2052 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2054 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2058 Menu *cutnpaste_menu = manage (new Menu);
2059 MenuList& cutnpaste_items = cutnpaste_menu->items();
2060 cutnpaste_menu->set_name ("ArdourContextMenu");
2062 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2063 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2064 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2066 Menu *nudge_menu = manage (new Menu());
2067 MenuList& nudge_items = nudge_menu->items();
2068 nudge_menu->set_name ("ArdourContextMenu");
2070 edit_items.push_back (SeparatorElem());
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2076 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2080 Editor::snap_type() const
2086 Editor::snap_mode() const
2092 Editor::set_snap_to (SnapType st)
2094 unsigned int snap_ind = (unsigned int)st;
2098 if (snap_ind > snap_type_strings.size() - 1) {
2100 _snap_type = (SnapType)snap_ind;
2103 string str = snap_type_strings[snap_ind];
2105 if (str != snap_type_selector.get_active_text()) {
2106 snap_type_selector.set_active_text (str);
2111 switch (_snap_type) {
2112 case SnapToBeatDiv128:
2113 case SnapToBeatDiv64:
2114 case SnapToBeatDiv32:
2115 case SnapToBeatDiv28:
2116 case SnapToBeatDiv24:
2117 case SnapToBeatDiv20:
2118 case SnapToBeatDiv16:
2119 case SnapToBeatDiv14:
2120 case SnapToBeatDiv12:
2121 case SnapToBeatDiv10:
2122 case SnapToBeatDiv8:
2123 case SnapToBeatDiv7:
2124 case SnapToBeatDiv6:
2125 case SnapToBeatDiv5:
2126 case SnapToBeatDiv4:
2127 case SnapToBeatDiv3:
2128 case SnapToBeatDiv2: {
2129 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2130 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2132 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2133 current_bbt_points_begin, current_bbt_points_end);
2134 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2135 current_bbt_points_begin, current_bbt_points_end);
2136 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2140 case SnapToRegionStart:
2141 case SnapToRegionEnd:
2142 case SnapToRegionSync:
2143 case SnapToRegionBoundary:
2144 build_region_boundary_cache ();
2152 SnapChanged (); /* EMIT SIGNAL */
2156 Editor::set_snap_mode (SnapMode mode)
2158 string str = snap_mode_strings[(int)mode];
2160 if (_internal_editing) {
2161 internal_snap_mode = mode;
2163 pre_internal_snap_mode = mode;
2168 if (str != snap_mode_selector.get_active_text ()) {
2169 snap_mode_selector.set_active_text (str);
2175 Editor::set_edit_point_preference (EditPoint ep, bool force)
2177 bool changed = (_edit_point != ep);
2180 string str = edit_point_strings[(int)ep];
2182 if (str != edit_point_selector.get_active_text ()) {
2183 edit_point_selector.set_active_text (str);
2186 set_canvas_cursor ();
2188 if (!force && !changed) {
2192 const char* action=NULL;
2194 switch (_edit_point) {
2195 case EditAtPlayhead:
2196 action = "edit-at-playhead";
2198 case EditAtSelectedMarker:
2199 action = "edit-at-marker";
2202 action = "edit-at-mouse";
2206 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2208 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2212 bool in_track_canvas;
2214 if (!mouse_frame (foo, in_track_canvas)) {
2215 in_track_canvas = false;
2218 reset_canvas_action_sensitivity (in_track_canvas);
2224 Editor::set_state (const XMLNode& node, int /*version*/)
2226 const XMLProperty* prop;
2233 g.base_width = default_width;
2234 g.base_height = default_height;
2238 if ((geometry = find_named_node (node, "geometry")) != 0) {
2242 if ((prop = geometry->property("x_size")) == 0) {
2243 prop = geometry->property ("x-size");
2246 g.base_width = atoi(prop->value());
2248 if ((prop = geometry->property("y_size")) == 0) {
2249 prop = geometry->property ("y-size");
2252 g.base_height = atoi(prop->value());
2255 if ((prop = geometry->property ("x_pos")) == 0) {
2256 prop = geometry->property ("x-pos");
2259 x = atoi (prop->value());
2262 if ((prop = geometry->property ("y_pos")) == 0) {
2263 prop = geometry->property ("y-pos");
2266 y = atoi (prop->value());
2270 set_default_size (g.base_width, g.base_height);
2273 if (_session && (prop = node.property ("playhead"))) {
2275 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2276 playhead_cursor->set_position (pos);
2278 playhead_cursor->set_position (0);
2281 if ((prop = node.property ("mixer-width"))) {
2282 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2285 if ((prop = node.property ("zoom-focus"))) {
2286 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2289 if ((prop = node.property ("zoom"))) {
2290 reset_zoom (PBD::atof (prop->value()));
2292 reset_zoom (frames_per_pixel);
2295 if ((prop = node.property ("snap-to"))) {
2296 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2299 if ((prop = node.property ("snap-mode"))) {
2300 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2303 if ((prop = node.property ("internal-snap-to"))) {
2304 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2307 if ((prop = node.property ("internal-snap-mode"))) {
2308 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2311 if ((prop = node.property ("pre-internal-snap-to"))) {
2312 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2316 if ((prop = node.property ("pre-internal-snap-mode"))) {
2317 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2320 if ((prop = node.property ("mouse-mode"))) {
2321 MouseMode m = str2mousemode(prop->value());
2322 set_mouse_mode (m, true);
2324 set_mouse_mode (MouseObject, true);
2327 if ((prop = node.property ("left-frame")) != 0) {
2329 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2333 reset_x_origin (pos);
2337 if ((prop = node.property ("y-origin")) != 0) {
2338 reset_y_origin (atof (prop->value ()));
2341 if ((prop = node.property ("internal-edit"))) {
2342 bool yn = string_is_affirmative (prop->value());
2343 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2345 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346 tact->set_active (!yn);
2347 tact->set_active (yn);
2351 if ((prop = node.property ("join-object-range"))) {
2352 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2353 bool yn = string_is_affirmative (prop->value());
2355 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2356 tact->set_active (!yn);
2357 tact->set_active (yn);
2359 set_mouse_mode(mouse_mode, true);
2362 if ((prop = node.property ("edit-point"))) {
2363 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2366 if ((prop = node.property ("show-measures"))) {
2367 bool yn = string_is_affirmative (prop->value());
2368 _show_measures = yn;
2369 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2371 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2372 /* do it twice to force the change */
2373 tact->set_active (!yn);
2374 tact->set_active (yn);
2378 if ((prop = node.property ("follow-playhead"))) {
2379 bool yn = string_is_affirmative (prop->value());
2380 set_follow_playhead (yn);
2381 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2383 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2384 if (tact->get_active() != yn) {
2385 tact->set_active (yn);
2390 if ((prop = node.property ("stationary-playhead"))) {
2391 bool yn = string_is_affirmative (prop->value());
2392 set_stationary_playhead (yn);
2393 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2395 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2396 if (tact->get_active() != yn) {
2397 tact->set_active (yn);
2402 if ((prop = node.property ("region-list-sort-type"))) {
2403 RegionListSortType st;
2404 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2407 if ((prop = node.property ("show-editor-mixer"))) {
2409 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2412 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2413 bool yn = string_is_affirmative (prop->value());
2415 /* do it twice to force the change */
2417 tact->set_active (!yn);
2418 tact->set_active (yn);
2421 if ((prop = node.property ("show-editor-list"))) {
2423 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2426 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2427 bool yn = string_is_affirmative (prop->value());
2429 /* do it twice to force the change */
2431 tact->set_active (!yn);
2432 tact->set_active (yn);
2435 if ((prop = node.property (X_("editor-list-page")))) {
2436 _the_notebook.set_current_page (atoi (prop->value ()));
2439 if ((prop = node.property (X_("show-marker-lines")))) {
2440 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2442 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2443 bool yn = string_is_affirmative (prop->value ());
2445 tact->set_active (!yn);
2446 tact->set_active (yn);
2449 XMLNodeList children = node.children ();
2450 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2451 selection->set_state (**i, Stateful::current_state_version);
2452 _regions->set_state (**i);
2455 if ((prop = node.property ("maximised"))) {
2456 bool yn = string_is_affirmative (prop->value());
2458 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2462 if ((prop = node.property ("nudge-clock-value"))) {
2464 sscanf (prop->value().c_str(), "%" PRId64, &f);
2465 nudge_clock->set (f);
2467 nudge_clock->set_mode (AudioClock::Timecode);
2468 nudge_clock->set (_session->frame_rate() * 5, true);
2475 Editor::get_state ()
2477 XMLNode* node = new XMLNode ("Editor");
2480 id().print (buf, sizeof (buf));
2481 node->add_property ("id", buf);
2483 if (is_realized()) {
2484 Glib::RefPtr<Gdk::Window> win = get_window();
2486 int x, y, width, height;
2487 win->get_root_origin(x, y);
2488 win->get_size(width, height);
2490 XMLNode* geometry = new XMLNode ("geometry");
2492 snprintf(buf, sizeof(buf), "%d", width);
2493 geometry->add_property("x-size", string(buf));
2494 snprintf(buf, sizeof(buf), "%d", height);
2495 geometry->add_property("y-size", string(buf));
2496 snprintf(buf, sizeof(buf), "%d", x);
2497 geometry->add_property("x-pos", string(buf));
2498 snprintf(buf, sizeof(buf), "%d", y);
2499 geometry->add_property("y-pos", string(buf));
2500 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2501 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2502 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2503 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2504 geometry->add_property("edit-vertical-pane-pos", string(buf));
2506 node->add_child_nocopy (*geometry);
2509 maybe_add_mixer_strip_width (*node);
2511 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2512 snprintf (buf, sizeof(buf), "%f", frames_per_pixel);
2513 node->add_property ("zoom", buf);
2514 node->add_property ("snap-to", enum_2_string (_snap_type));
2515 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2516 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2517 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2518 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2519 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2520 node->add_property ("edit-point", enum_2_string (_edit_point));
2522 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2523 node->add_property ("playhead", buf);
2524 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2525 node->add_property ("left-frame", buf);
2526 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2527 node->add_property ("y-origin", buf);
2529 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2530 node->add_property ("maximised", _maximised ? "yes" : "no");
2531 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2532 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2533 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2534 node->add_property ("mouse-mode", enum2str(mouse_mode));
2535 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2536 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2538 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2540 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2541 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2544 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2546 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2547 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2550 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2551 node->add_property (X_("editor-list-page"), buf);
2553 if (button_bindings) {
2554 XMLNode* bb = new XMLNode (X_("Buttons"));
2555 button_bindings->save (*bb);
2556 node->add_child_nocopy (*bb);
2559 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2561 node->add_child_nocopy (selection->get_state ());
2562 node->add_child_nocopy (_regions->get_state ());
2564 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2565 node->add_property ("nudge-clock-value", buf);
2572 /** @param y y offset from the top of all trackviews.
2573 * @return pair: TimeAxisView that y is over, layer index.
2574 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2575 * in stacked or expanded region display mode, otherwise 0.
2577 std::pair<TimeAxisView *, double>
2578 Editor::trackview_by_y_position (double y)
2580 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2582 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2588 return std::make_pair ( (TimeAxisView *) 0, 0);
2591 /** Snap a position to the grid, if appropriate, taking into account current
2592 * grid settings and also the state of any snap modifier keys that may be pressed.
2593 * @param start Position to snap.
2594 * @param event Event to get current key modifier information from, or 0.
2597 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2599 if (!_session || !event) {
2603 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2604 if (_snap_mode == SnapOff) {
2605 snap_to_internal (start, direction, for_mark);
2608 if (_snap_mode != SnapOff) {
2609 snap_to_internal (start, direction, for_mark);
2615 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2617 if (!_session || _snap_mode == SnapOff) {
2621 snap_to_internal (start, direction, for_mark);
2625 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2627 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2628 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2630 switch (_snap_type) {
2631 case SnapToTimecodeFrame:
2632 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2633 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2635 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2639 case SnapToTimecodeSeconds:
2640 if (_session->config.get_timecode_offset_negative()) {
2641 start += _session->config.get_timecode_offset ();
2643 start -= _session->config.get_timecode_offset ();
2645 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2646 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2648 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2651 if (_session->config.get_timecode_offset_negative()) {
2652 start -= _session->config.get_timecode_offset ();
2654 start += _session->config.get_timecode_offset ();
2658 case SnapToTimecodeMinutes:
2659 if (_session->config.get_timecode_offset_negative()) {
2660 start += _session->config.get_timecode_offset ();
2662 start -= _session->config.get_timecode_offset ();
2664 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2665 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2667 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2669 if (_session->config.get_timecode_offset_negative()) {
2670 start -= _session->config.get_timecode_offset ();
2672 start += _session->config.get_timecode_offset ();
2676 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2682 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2684 const framepos_t one_second = _session->frame_rate();
2685 const framepos_t one_minute = _session->frame_rate() * 60;
2686 framepos_t presnap = start;
2690 switch (_snap_type) {
2691 case SnapToTimecodeFrame:
2692 case SnapToTimecodeSeconds:
2693 case SnapToTimecodeMinutes:
2694 return timecode_snap_to_internal (start, direction, for_mark);
2697 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2698 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2700 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2705 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2706 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2708 start = (framepos_t) floor ((double) start / one_second) * one_second;
2713 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2714 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2716 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2721 start = _session->tempo_map().round_to_bar (start, direction);
2725 start = _session->tempo_map().round_to_beat (start, direction);
2728 case SnapToBeatDiv128:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2731 case SnapToBeatDiv64:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2734 case SnapToBeatDiv32:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2737 case SnapToBeatDiv28:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2740 case SnapToBeatDiv24:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2743 case SnapToBeatDiv20:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2746 case SnapToBeatDiv16:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2749 case SnapToBeatDiv14:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2752 case SnapToBeatDiv12:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2755 case SnapToBeatDiv10:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2758 case SnapToBeatDiv8:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2761 case SnapToBeatDiv7:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2764 case SnapToBeatDiv6:
2765 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2767 case SnapToBeatDiv5:
2768 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2770 case SnapToBeatDiv4:
2771 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2773 case SnapToBeatDiv3:
2774 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2776 case SnapToBeatDiv2:
2777 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2785 _session->locations()->marks_either_side (start, before, after);
2787 if (before == max_framepos && after == max_framepos) {
2788 /* No marks to snap to, so just don't snap */
2790 } else if (before == max_framepos) {
2792 } else if (after == max_framepos) {
2794 } else if (before != max_framepos && after != max_framepos) {
2795 /* have before and after */
2796 if ((start - before) < (after - start)) {
2805 case SnapToRegionStart:
2806 case SnapToRegionEnd:
2807 case SnapToRegionSync:
2808 case SnapToRegionBoundary:
2809 if (!region_boundary_cache.empty()) {
2811 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2812 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2814 if (direction > 0) {
2815 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2817 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2820 if (next != region_boundary_cache.begin ()) {
2825 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2826 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2828 if (start > (p + n) / 2) {
2837 switch (_snap_mode) {
2843 if (presnap > start) {
2844 if (presnap > (start + unit_to_frame(snap_threshold))) {
2848 } else if (presnap < start) {
2849 if (presnap < (start - unit_to_frame(snap_threshold))) {
2855 /* handled at entry */
2863 Editor::setup_toolbar ()
2865 HBox* mode_box = manage(new HBox);
2866 mode_box->set_border_width (2);
2867 mode_box->set_spacing(4);
2869 HBox* mouse_mode_box = manage (new HBox);
2870 HBox* mouse_mode_hbox = manage (new HBox);
2871 VBox* mouse_mode_vbox = manage (new VBox);
2872 Alignment* mouse_mode_align = manage (new Alignment);
2874 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2875 // mouse_mode_size_group->add_widget (smart_mode_button);
2876 mouse_mode_size_group->add_widget (mouse_move_button);
2877 mouse_mode_size_group->add_widget (mouse_select_button);
2878 mouse_mode_size_group->add_widget (mouse_zoom_button);
2879 mouse_mode_size_group->add_widget (mouse_gain_button);
2880 mouse_mode_size_group->add_widget (mouse_timefx_button);
2881 mouse_mode_size_group->add_widget (mouse_audition_button);
2882 mouse_mode_size_group->add_widget (mouse_draw_button);
2883 mouse_mode_size_group->add_widget (internal_edit_button);
2885 /* make them just a bit bigger */
2886 mouse_move_button.set_size_request (-1, 30);
2888 mouse_mode_hbox->set_spacing (2);
2890 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2898 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 ("EditModeSelector");
2914 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2915 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2917 mode_box->pack_start (edit_mode_selector, false, false);
2918 mode_box->pack_start (*mouse_mode_box, false, false);
2920 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2921 _mouse_mode_tearoff->set_name ("MouseModeBase");
2922 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2924 if (Profile->get_sae()) {
2925 _mouse_mode_tearoff->set_can_be_torn_off (false);
2928 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window()));
2930 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window(), 1));
2932 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2933 &_mouse_mode_tearoff->tearoff_window()));
2934 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2935 &_mouse_mode_tearoff->tearoff_window(), 1));
2939 _zoom_box.set_spacing (2);
2940 _zoom_box.set_border_width (2);
2944 zoom_in_button.set_name ("zoom button");
2945 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2946 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2947 zoom_in_button.set_image(::get_icon ("zoom_in"));
2948 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2949 zoom_in_button.set_related_action (act);
2951 zoom_out_button.set_name ("zoom button");
2952 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2953 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2954 zoom_out_button.set_image(::get_icon ("zoom_out"));
2955 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2956 zoom_out_button.set_related_action (act);
2958 zoom_out_full_button.set_name ("zoom button");
2959 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2960 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2961 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2962 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2963 zoom_out_full_button.set_related_action (act);
2965 zoom_focus_selector.set_name ("ZoomFocusSelector");
2966 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2967 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2969 _zoom_box.pack_start (zoom_out_button, false, false);
2970 _zoom_box.pack_start (zoom_in_button, false, false);
2971 _zoom_box.pack_start (zoom_out_full_button, false, false);
2973 _zoom_box.pack_start (zoom_focus_selector, false, false);
2975 /* Track zoom buttons */
2976 tav_expand_button.set_name ("zoom button");
2977 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2978 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2979 tav_expand_button.set_size_request (-1, 20);
2980 tav_expand_button.set_image(::get_icon ("tav_exp"));
2981 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2982 tav_expand_button.set_related_action (act);
2984 tav_shrink_button.set_name ("zoom button");
2985 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2986 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2987 tav_shrink_button.set_size_request (-1, 20);
2988 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2989 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2990 tav_shrink_button.set_related_action (act);
2992 _zoom_box.pack_start (tav_shrink_button);
2993 _zoom_box.pack_start (tav_expand_button);
2995 _zoom_tearoff = manage (new TearOff (_zoom_box));
2997 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2998 &_zoom_tearoff->tearoff_window()));
2999 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3000 &_zoom_tearoff->tearoff_window(), 0));
3001 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3002 &_zoom_tearoff->tearoff_window()));
3003 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3004 &_zoom_tearoff->tearoff_window(), 0));
3006 snap_box.set_spacing (2);
3007 snap_box.set_border_width (2);
3009 snap_type_selector.set_name ("SnapTypeSelector");
3010 set_popdown_strings (snap_type_selector, snap_type_strings);
3011 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3013 snap_mode_selector.set_name ("SnapModeSelector");
3014 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3015 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3017 edit_point_selector.set_name ("EditPointSelector");
3018 set_popdown_strings (edit_point_selector, edit_point_strings);
3019 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3021 snap_box.pack_start (snap_mode_selector, false, false);
3022 snap_box.pack_start (snap_type_selector, false, false);
3023 snap_box.pack_start (edit_point_selector, false, false);
3027 HBox *nudge_box = manage (new HBox);
3028 nudge_box->set_spacing (2);
3029 nudge_box->set_border_width (2);
3031 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3032 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3034 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3035 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3037 nudge_box->pack_start (nudge_backward_button, false, false);
3038 nudge_box->pack_start (nudge_forward_button, false, false);
3039 nudge_box->pack_start (*nudge_clock, false, false);
3042 /* Pack everything in... */
3044 HBox* hbox = manage (new HBox);
3045 hbox->set_spacing(10);
3047 _tools_tearoff = manage (new TearOff (*hbox));
3048 _tools_tearoff->set_name ("MouseModeBase");
3049 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3051 if (Profile->get_sae()) {
3052 _tools_tearoff->set_can_be_torn_off (false);
3055 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3056 &_tools_tearoff->tearoff_window()));
3057 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3058 &_tools_tearoff->tearoff_window(), 0));
3059 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3060 &_tools_tearoff->tearoff_window()));
3061 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3062 &_tools_tearoff->tearoff_window(), 0));
3064 toolbar_hbox.set_spacing (10);
3065 toolbar_hbox.set_border_width (1);
3067 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3068 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3069 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3071 hbox->pack_start (snap_box, false, false);
3072 if (!Profile->get_small_screen()) {
3073 hbox->pack_start (*nudge_box, false, false);
3075 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3077 hbox->pack_start (panic_box, false, false);
3081 toolbar_base.set_name ("ToolBarBase");
3082 toolbar_base.add (toolbar_hbox);
3084 _toolbar_viewport.add (toolbar_base);
3085 /* stick to the required height but allow width to vary if there's not enough room */
3086 _toolbar_viewport.set_size_request (1, -1);
3088 toolbar_frame.set_shadow_type (SHADOW_OUT);
3089 toolbar_frame.set_name ("BaseFrame");
3090 toolbar_frame.add (_toolbar_viewport);
3094 Editor::setup_tooltips ()
3096 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3097 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3098 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3099 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3100 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3101 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3102 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3103 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3104 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3105 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3106 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3107 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3108 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3109 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3110 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3111 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3112 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3113 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3114 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3115 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3116 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3117 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3118 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3122 Editor::convert_drop_to_paths (
3123 vector<string>& paths,
3124 const RefPtr<Gdk::DragContext>& /*context*/,
3127 const SelectionData& data,
3131 if (_session == 0) {
3135 vector<string> uris = data.get_uris();
3139 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3140 are actually URI lists. So do it by hand.
3143 if (data.get_target() != "text/plain") {
3147 /* Parse the "uri-list" format that Nautilus provides,
3148 where each pathname is delimited by \r\n.
3150 THERE MAY BE NO NULL TERMINATING CHAR!!!
3153 string txt = data.get_text();
3157 p = (const char *) malloc (txt.length() + 1);
3158 txt.copy (const_cast<char *> (p), txt.length(), 0);
3159 const_cast<char*>(p)[txt.length()] = '\0';
3165 while (g_ascii_isspace (*p))
3169 while (*q && (*q != '\n') && (*q != '\r')) {
3176 while (q > p && g_ascii_isspace (*q))
3181 uris.push_back (string (p, q - p + 1));
3185 p = strchr (p, '\n');
3197 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3199 if ((*i).substr (0,7) == "file://") {
3201 string const p = PBD::url_decode (*i);
3203 // scan forward past three slashes
3205 string::size_type slashcnt = 0;
3206 string::size_type n = 0;
3207 string::const_iterator x = p.begin();
3209 while (slashcnt < 3 && x != p.end()) {
3212 } else if (slashcnt == 3) {
3219 if (slashcnt != 3 || x == p.end()) {
3220 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3224 paths.push_back (p.substr (n - 1));
3232 Editor::new_tempo_section ()
3238 Editor::map_transport_state ()
3240 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3242 if (_session && _session->transport_stopped()) {
3243 have_pending_keyboard_selection = false;
3246 update_loop_range_view (true);
3252 Editor::begin_reversible_command (string name)
3255 _session->begin_reversible_command (name);
3260 Editor::begin_reversible_command (GQuark q)
3263 _session->begin_reversible_command (q);
3268 Editor::commit_reversible_command ()
3271 _session->commit_reversible_command ();
3276 Editor::history_changed ()
3280 if (undo_action && _session) {
3281 if (_session->undo_depth() == 0) {
3282 label = S_("Command|Undo");
3284 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3286 undo_action->property_label() = label;
3289 if (redo_action && _session) {
3290 if (_session->redo_depth() == 0) {
3293 label = string_compose(_("Redo (%1)"), _session->next_redo());
3295 redo_action->property_label() = label;
3300 Editor::duplicate_range (bool with_dialog)
3304 RegionSelection rs = get_regions_from_selection_and_entered ();
3306 if ( selection->time.length() == 0 && rs.empty()) {
3312 ArdourDialog win (_("Duplicate"));
3313 Label label (_("Number of duplications:"));
3314 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3315 SpinButton spinner (adjustment, 0.0, 1);
3318 win.get_vbox()->set_spacing (12);
3319 win.get_vbox()->pack_start (hbox);
3320 hbox.set_border_width (6);
3321 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3323 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3324 place, visually. so do this by hand.
3327 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3328 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3329 spinner.grab_focus();
3335 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3336 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3337 win.set_default_response (RESPONSE_ACCEPT);
3339 win.set_position (WIN_POS_MOUSE);
3341 spinner.grab_focus ();
3343 switch (win.run ()) {
3344 case RESPONSE_ACCEPT:
3350 times = adjustment.get_value();
3353 if ((current_mouse_mode() == Editing::MouseRange)) {
3354 if (selection->time.length()) {
3355 duplicate_selection (times);
3357 } else if (get_smart_mode()) {
3358 if (selection->time.length()) {
3359 duplicate_selection (times);
3361 duplicate_some_regions (rs, times);
3363 duplicate_some_regions (rs, times);
3368 Editor::set_edit_mode (EditMode m)
3370 Config->set_edit_mode (m);
3374 Editor::cycle_edit_mode ()
3376 switch (Config->get_edit_mode()) {
3378 if (Profile->get_sae()) {
3379 Config->set_edit_mode (Lock);
3381 Config->set_edit_mode (Splice);
3385 Config->set_edit_mode (Lock);
3388 Config->set_edit_mode (Slide);
3394 Editor::edit_mode_selection_done ()
3396 string s = edit_mode_selector.get_active_text ();
3399 Config->set_edit_mode (string_to_edit_mode (s));
3404 Editor::snap_type_selection_done ()
3406 string choice = snap_type_selector.get_active_text();
3407 SnapType snaptype = SnapToBeat;
3409 if (choice == _("Beats/2")) {
3410 snaptype = SnapToBeatDiv2;
3411 } else if (choice == _("Beats/3")) {
3412 snaptype = SnapToBeatDiv3;
3413 } else if (choice == _("Beats/4")) {
3414 snaptype = SnapToBeatDiv4;
3415 } else if (choice == _("Beats/5")) {
3416 snaptype = SnapToBeatDiv5;
3417 } else if (choice == _("Beats/6")) {
3418 snaptype = SnapToBeatDiv6;
3419 } else if (choice == _("Beats/7")) {
3420 snaptype = SnapToBeatDiv7;
3421 } else if (choice == _("Beats/8")) {
3422 snaptype = SnapToBeatDiv8;
3423 } else if (choice == _("Beats/10")) {
3424 snaptype = SnapToBeatDiv10;
3425 } else if (choice == _("Beats/12")) {
3426 snaptype = SnapToBeatDiv12;
3427 } else if (choice == _("Beats/14")) {
3428 snaptype = SnapToBeatDiv14;
3429 } else if (choice == _("Beats/16")) {
3430 snaptype = SnapToBeatDiv16;
3431 } else if (choice == _("Beats/20")) {
3432 snaptype = SnapToBeatDiv20;
3433 } else if (choice == _("Beats/24")) {
3434 snaptype = SnapToBeatDiv24;
3435 } else if (choice == _("Beats/28")) {
3436 snaptype = SnapToBeatDiv28;
3437 } else if (choice == _("Beats/32")) {
3438 snaptype = SnapToBeatDiv32;
3439 } else if (choice == _("Beats/64")) {
3440 snaptype = SnapToBeatDiv64;
3441 } else if (choice == _("Beats/128")) {
3442 snaptype = SnapToBeatDiv128;
3443 } else if (choice == _("Beats")) {
3444 snaptype = SnapToBeat;
3445 } else if (choice == _("Bars")) {
3446 snaptype = SnapToBar;
3447 } else if (choice == _("Marks")) {
3448 snaptype = SnapToMark;
3449 } else if (choice == _("Region starts")) {
3450 snaptype = SnapToRegionStart;
3451 } else if (choice == _("Region ends")) {
3452 snaptype = SnapToRegionEnd;
3453 } else if (choice == _("Region bounds")) {
3454 snaptype = SnapToRegionBoundary;
3455 } else if (choice == _("Region syncs")) {
3456 snaptype = SnapToRegionSync;
3457 } else if (choice == _("CD Frames")) {
3458 snaptype = SnapToCDFrame;
3459 } else if (choice == _("Timecode Frames")) {
3460 snaptype = SnapToTimecodeFrame;
3461 } else if (choice == _("Timecode Seconds")) {
3462 snaptype = SnapToTimecodeSeconds;
3463 } else if (choice == _("Timecode Minutes")) {
3464 snaptype = SnapToTimecodeMinutes;
3465 } else if (choice == _("Seconds")) {
3466 snaptype = SnapToSeconds;
3467 } else if (choice == _("Minutes")) {
3468 snaptype = SnapToMinutes;
3471 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3473 ract->set_active ();
3478 Editor::snap_mode_selection_done ()
3480 string choice = snap_mode_selector.get_active_text();
3481 SnapMode mode = SnapNormal;
3483 if (choice == _("No Grid")) {
3485 } else if (choice == _("Grid")) {
3487 } else if (choice == _("Magnetic")) {
3488 mode = SnapMagnetic;
3491 RefPtr<RadioAction> ract = snap_mode_action (mode);
3494 ract->set_active (true);
3499 Editor::cycle_edit_point (bool with_marker)
3501 switch (_edit_point) {
3503 set_edit_point_preference (EditAtPlayhead);
3505 case EditAtPlayhead:
3507 set_edit_point_preference (EditAtSelectedMarker);
3509 set_edit_point_preference (EditAtMouse);
3512 case EditAtSelectedMarker:
3513 set_edit_point_preference (EditAtMouse);
3519 Editor::edit_point_selection_done ()
3521 string choice = edit_point_selector.get_active_text();
3522 EditPoint ep = EditAtSelectedMarker;
3524 if (choice == _("Marker")) {
3525 set_edit_point_preference (EditAtSelectedMarker);
3526 } else if (choice == _("Playhead")) {
3527 set_edit_point_preference (EditAtPlayhead);
3529 set_edit_point_preference (EditAtMouse);
3532 RefPtr<RadioAction> ract = edit_point_action (ep);
3535 ract->set_active (true);
3540 Editor::zoom_focus_selection_done ()
3542 string choice = zoom_focus_selector.get_active_text();
3543 ZoomFocus focus_type = ZoomFocusLeft;
3545 if (choice == _("Left")) {
3546 focus_type = ZoomFocusLeft;
3547 } else if (choice == _("Right")) {
3548 focus_type = ZoomFocusRight;
3549 } else if (choice == _("Center")) {
3550 focus_type = ZoomFocusCenter;
3551 } else if (choice == _("Playhead")) {
3552 focus_type = ZoomFocusPlayhead;
3553 } else if (choice == _("Mouse")) {
3554 focus_type = ZoomFocusMouse;
3555 } else if (choice == _("Edit point")) {
3556 focus_type = ZoomFocusEdit;
3559 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3562 ract->set_active ();
3567 Editor::edit_controls_button_release (GdkEventButton* ev)
3569 if (Keyboard::is_context_menu_event (ev)) {
3570 ARDOUR_UI::instance()->add_route (this);
3571 } else if (ev->button == 1) {
3572 selection->clear_tracks ();
3579 Editor::mouse_select_button_release (GdkEventButton* ev)
3581 /* this handles just right-clicks */
3583 if (ev->button != 3) {
3591 Editor::set_zoom_focus (ZoomFocus f)
3593 string str = zoom_focus_strings[(int)f];
3595 if (str != zoom_focus_selector.get_active_text()) {
3596 zoom_focus_selector.set_active_text (str);
3599 if (zoom_focus != f) {
3606 Editor::cycle_zoom_focus ()
3608 switch (zoom_focus) {
3610 set_zoom_focus (ZoomFocusRight);
3612 case ZoomFocusRight:
3613 set_zoom_focus (ZoomFocusCenter);
3615 case ZoomFocusCenter:
3616 set_zoom_focus (ZoomFocusPlayhead);
3618 case ZoomFocusPlayhead:
3619 set_zoom_focus (ZoomFocusMouse);
3621 case ZoomFocusMouse:
3622 set_zoom_focus (ZoomFocusEdit);
3625 set_zoom_focus (ZoomFocusLeft);
3631 Editor::ensure_float (Window& win)
3633 win.set_transient_for (*this);
3637 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3639 /* recover or initialize pane positions. do this here rather than earlier because
3640 we don't want the positions to change the child allocations, which they seem to do.
3646 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3655 XMLNode* geometry = find_named_node (*node, "geometry");
3657 if (which == static_cast<Paned*> (&edit_pane)) {
3659 if (done & Horizontal) {
3663 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3664 _notebook_shrunk = string_is_affirmative (prop->value ());
3667 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3668 /* initial allocation is 90% to canvas, 10% to notebook */
3669 pos = (int) floor (alloc.get_width() * 0.90f);
3670 snprintf (buf, sizeof(buf), "%d", pos);
3672 pos = atoi (prop->value());
3675 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3676 edit_pane.set_position (pos);
3679 done = (Pane) (done | Horizontal);
3681 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3683 if (done & Vertical) {
3687 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3688 /* initial allocation is 90% to canvas, 10% to summary */
3689 pos = (int) floor (alloc.get_height() * 0.90f);
3690 snprintf (buf, sizeof(buf), "%d", pos);
3693 pos = atoi (prop->value());
3696 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3697 editor_summary_pane.set_position (pos);
3700 done = (Pane) (done | Vertical);
3705 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3707 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3708 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3709 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3710 top_hbox.remove (toolbar_frame);
3715 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3717 if (toolbar_frame.get_parent() == 0) {
3718 top_hbox.pack_end (toolbar_frame);
3723 Editor::set_show_measures (bool yn)
3725 if (_show_measures != yn) {
3728 if ((_show_measures = yn) == true) {
3730 tempo_lines->show();
3732 (void) redraw_measures ();
3739 Editor::toggle_follow_playhead ()
3741 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3743 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3744 set_follow_playhead (tact->get_active());
3748 /** @param yn true to follow playhead, otherwise false.
3749 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3752 Editor::set_follow_playhead (bool yn, bool catch_up)
3754 if (_follow_playhead != yn) {
3755 if ((_follow_playhead = yn) == true && catch_up) {
3757 reset_x_origin_to_follow_playhead ();
3764 Editor::toggle_stationary_playhead ()
3766 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3768 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3769 set_stationary_playhead (tact->get_active());
3774 Editor::set_stationary_playhead (bool yn)
3776 if (_stationary_playhead != yn) {
3777 if ((_stationary_playhead = yn) == true) {
3779 // FIXME need a 3.0 equivalent of this 2.X call
3780 // update_current_screen ();
3787 Editor::playlist_selector () const
3789 return *_playlist_selector;
3793 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3797 switch (_snap_type) {
3802 case SnapToBeatDiv128:
3805 case SnapToBeatDiv64:
3808 case SnapToBeatDiv32:
3811 case SnapToBeatDiv28:
3814 case SnapToBeatDiv24:
3817 case SnapToBeatDiv20:
3820 case SnapToBeatDiv16:
3823 case SnapToBeatDiv14:
3826 case SnapToBeatDiv12:
3829 case SnapToBeatDiv10:
3832 case SnapToBeatDiv8:
3835 case SnapToBeatDiv7:
3838 case SnapToBeatDiv6:
3841 case SnapToBeatDiv5:
3844 case SnapToBeatDiv4:
3847 case SnapToBeatDiv3:
3850 case SnapToBeatDiv2:
3856 return _session->tempo_map().meter_at (position).divisions_per_bar();
3861 case SnapToTimecodeFrame:
3862 case SnapToTimecodeSeconds:
3863 case SnapToTimecodeMinutes:
3866 case SnapToRegionStart:
3867 case SnapToRegionEnd:
3868 case SnapToRegionSync:
3869 case SnapToRegionBoundary:
3879 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3883 ret = nudge_clock->current_duration (pos);
3884 next = ret + 1; /* XXXX fix me */
3890 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3892 ArdourDialog dialog (_("Playlist Deletion"));
3893 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3894 "If it is kept, its audio files will not be cleaned.\n"
3895 "If it is deleted, audio files used by it alone will be cleaned."),
3898 dialog.set_position (WIN_POS_CENTER);
3899 dialog.get_vbox()->pack_start (label);
3903 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3904 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3905 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3907 switch (dialog.run ()) {
3908 case RESPONSE_ACCEPT:
3909 /* delete the playlist */
3913 case RESPONSE_REJECT:
3914 /* keep the playlist */
3926 Editor::audio_region_selection_covers (framepos_t where)
3928 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3929 if ((*a)->region()->covers (where)) {
3938 Editor::prepare_for_cleanup ()
3940 cut_buffer->clear_regions ();
3941 cut_buffer->clear_playlists ();
3943 selection->clear_regions ();
3944 selection->clear_playlists ();
3946 _regions->suspend_redisplay ();
3950 Editor::finish_cleanup ()
3952 _regions->resume_redisplay ();
3956 Editor::transport_loop_location()
3959 return _session->locations()->auto_loop_location();
3966 Editor::transport_punch_location()
3969 return _session->locations()->auto_punch_location();
3976 Editor::control_layout_scroll (GdkEventScroll* ev)
3978 if (Keyboard::some_magic_widget_has_focus()) {
3982 switch (ev->direction) {
3984 scroll_tracks_up_line ();
3988 case GDK_SCROLL_DOWN:
3989 scroll_tracks_down_line ();
3993 /* no left/right handling yet */
4001 Editor::session_state_saved (string)
4004 _snapshots->redisplay ();
4008 Editor::update_tearoff_visibility()
4010 bool visible = Config->get_keep_tearoffs();
4011 _mouse_mode_tearoff->set_visible (visible);
4012 _tools_tearoff->set_visible (visible);
4013 _zoom_tearoff->set_visible (visible);
4017 Editor::maximise_editing_space ()
4029 Editor::restore_editing_space ()
4041 * Make new playlists for a given track and also any others that belong
4042 * to the same active route group with the `edit' property.
4047 Editor::new_playlists (TimeAxisView* v)
4049 begin_reversible_command (_("new playlists"));
4050 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4051 _session->playlists->get (playlists);
4052 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4053 commit_reversible_command ();
4057 * Use a copy of the current playlist for a given track and also any others that belong
4058 * to the same active route group with the `edit' property.
4063 Editor::copy_playlists (TimeAxisView* v)
4065 begin_reversible_command (_("copy playlists"));
4066 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4067 _session->playlists->get (playlists);
4068 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4069 commit_reversible_command ();
4072 /** Clear the current playlist for a given track and also any others that belong
4073 * to the same active route group with the `edit' property.
4078 Editor::clear_playlists (TimeAxisView* v)
4080 begin_reversible_command (_("clear playlists"));
4081 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4082 _session->playlists->get (playlists);
4083 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4084 commit_reversible_command ();
4088 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4090 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4094 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4096 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4100 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4102 atv.clear_playlist ();
4106 Editor::on_key_press_event (GdkEventKey* ev)
4108 return key_press_focus_accelerator_handler (*this, ev);
4112 Editor::on_key_release_event (GdkEventKey* ev)
4114 return Gtk::Window::on_key_release_event (ev);
4115 // return key_press_focus_accelerator_handler (*this, ev);
4118 /** Queue up a change to the viewport x origin.
4119 * @param frame New x origin.
4122 Editor::reset_x_origin (framepos_t frame)
4124 pending_visual_change.add (VisualChange::TimeOrigin);
4125 pending_visual_change.time_origin = frame;
4126 ensure_visual_change_idle_handler ();
4130 Editor::reset_y_origin (double y)
4132 pending_visual_change.add (VisualChange::YOrigin);
4133 pending_visual_change.y_origin = y;
4134 ensure_visual_change_idle_handler ();
4138 Editor::reset_zoom (double fpp)
4140 clamp_frames_per_pixel (fpp);
4142 if (fpp == frames_per_pixel) {
4146 pending_visual_change.add (VisualChange::ZoomLevel);
4147 pending_visual_change.frames_per_pixel = fpp;
4148 ensure_visual_change_idle_handler ();
4152 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4154 reset_x_origin (frame);
4157 if (!no_save_visual) {
4158 undo_visual_stack.push_back (current_visual_state(false));
4162 Editor::VisualState::VisualState (bool with_tracks)
4163 : gui_state (with_tracks ? new GUIObjectState : 0)
4167 Editor::VisualState::~VisualState ()
4172 Editor::VisualState*
4173 Editor::current_visual_state (bool with_tracks)
4175 VisualState* vs = new VisualState (with_tracks);
4176 vs->y_position = vertical_adjustment.get_value();
4177 vs->frames_per_pixel = frames_per_pixel;
4178 vs->leftmost_frame = leftmost_frame;
4179 vs->zoom_focus = zoom_focus;
4182 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4189 Editor::undo_visual_state ()
4191 if (undo_visual_stack.empty()) {
4195 VisualState* vs = undo_visual_stack.back();
4196 undo_visual_stack.pop_back();
4199 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4201 use_visual_state (*vs);
4205 Editor::redo_visual_state ()
4207 if (redo_visual_stack.empty()) {
4211 VisualState* vs = redo_visual_stack.back();
4212 redo_visual_stack.pop_back();
4214 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4216 use_visual_state (*vs);
4220 Editor::swap_visual_state ()
4222 if (undo_visual_stack.empty()) {
4223 redo_visual_state ();
4225 undo_visual_state ();
4230 Editor::use_visual_state (VisualState& vs)
4232 PBD::Unwinder<bool> nsv (no_save_visual, true);
4234 _routes->suspend_redisplay ();
4236 vertical_adjustment.set_value (vs.y_position);
4238 set_zoom_focus (vs.zoom_focus);
4239 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_pixel);
4242 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4244 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4245 (*i)->reset_visual_state ();
4249 _routes->update_visibility ();
4250 _routes->resume_redisplay ();
4253 /** This is the core function that controls the zoom level of the canvas. It is called
4254 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4255 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4258 Editor::set_frames_per_pixel (double fpp)
4261 tempo_lines->tempo_map_changed();
4264 frames_per_pixel = fpp;
4266 /* convert fpu to frame count */
4268 framepos_t frames = (framepos_t) floor (frames_per_pixel * _visible_canvas_width);
4270 if (frames_per_pixel != zoom_range_clock->current_duration()) {
4271 zoom_range_clock->set (frames);
4274 bool const showing_time_selection = selection->time.length() > 0;
4276 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4277 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4278 (*i)->reshow_selection (selection->time);
4282 ZoomChanged (); /* EMIT_SIGNAL */
4284 //reset_scrolling_region ();
4286 if (playhead_cursor) {
4287 playhead_cursor->set_position (playhead_cursor->current_frame ());
4290 refresh_location_display();
4291 _summary->set_overlays_dirty ();
4293 update_marker_labels ();
4298 #ifdef WITH_VIDEOTIMELINE
4300 Editor::queue_visual_videotimeline_update ()
4303 * pending_visual_change.add (VisualChange::VideoTimeline);
4304 * or maybe even more specific: which videotimeline-image
4305 * currently it calls update_video_timeline() to update
4306 * _all outdated_ images on the video-timeline.
4307 * see 'exposeimg()' in video_image_frame.cc
4309 ensure_visual_change_idle_handler ();
4314 Editor::ensure_visual_change_idle_handler ()
4316 if (pending_visual_change.idle_handler_id < 0) {
4317 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4318 pending_visual_change.executing = false;
4323 Editor::_idle_visual_changer (void* arg)
4325 return static_cast<Editor*>(arg)->idle_visual_changer ();
4329 Editor::idle_visual_changer ()
4331 /* set_horizontal_position() below (and maybe other calls) call
4332 gtk_main_iteration(), so it's possible that a signal will be handled
4333 half-way through this method. If this signal wants an
4334 idle_visual_changer we must schedule another one after this one, so
4335 mark the idle_handler_id as -1 here to allow that. Also make a note
4336 that we are doing the visual change, so that changes in response to
4337 super-rapid-screen-update can be dropped if we are still processing
4341 pending_visual_change.idle_handler_id = -1;
4342 pending_visual_change.being_handled = true;
4344 VisualChange::Type p = pending_visual_change.pending;
4345 pending_visual_change.pending = (VisualChange::Type) 0;
4347 double const last_time_origin = horizontal_position ();
4349 if (p & VisualChange::ZoomLevel) {
4350 set_frames_per_pixel (pending_visual_change.frames_per_pixel);
4352 compute_fixed_ruler_scale ();
4354 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4355 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4357 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4358 current_bbt_points_begin, current_bbt_points_end);
4359 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4360 current_bbt_points_begin, current_bbt_points_end);
4361 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4364 #ifdef WITH_VIDEOTIMELINE
4365 if (p & VisualChange::ZoomLevel) {
4366 update_video_timeline();
4370 if (p & VisualChange::TimeOrigin) {
4371 set_horizontal_position (pending_visual_change.time_origin / frames_per_pixel);
4374 if (p & VisualChange::YOrigin) {
4375 vertical_adjustment.set_value (pending_visual_change.y_origin);
4378 if (last_time_origin == horizontal_position ()) {
4379 /* changed signal not emitted */
4380 update_fixed_rulers ();
4381 redisplay_tempo (true);
4383 #ifdef WITH_VIDEOTIMELINE
4384 if (!(p & VisualChange::ZoomLevel)) {
4385 update_video_timeline();
4389 _summary->set_overlays_dirty ();
4391 pending_visual_change.being_handled = false;
4392 return 0; /* this is always a one-shot call */
4395 struct EditorOrderTimeAxisSorter {
4396 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4397 return a->order () < b->order ();
4402 Editor::sort_track_selection (TrackViewList& sel)
4404 EditorOrderTimeAxisSorter cmp;
4409 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4412 framepos_t where = 0;
4413 EditPoint ep = _edit_point;
4415 if (from_context_menu && (ep == EditAtMouse)) {
4416 return event_frame (&context_click_event, 0, 0);
4419 if (entered_marker) {
4420 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4421 return entered_marker->position();
4424 if (ignore_playhead && ep == EditAtPlayhead) {
4425 ep = EditAtSelectedMarker;
4429 case EditAtPlayhead:
4430 where = _session->audible_frame();
4431 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4434 case EditAtSelectedMarker:
4435 if (!selection->markers.empty()) {
4437 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4440 where = loc->start();
4444 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4452 if (!mouse_frame (where, ignored)) {
4453 /* XXX not right but what can we do ? */
4457 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4465 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4467 if (!_session) return;
4469 begin_reversible_command (cmd);
4473 if ((tll = transport_loop_location()) == 0) {
4474 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4475 XMLNode &before = _session->locations()->get_state();
4476 _session->locations()->add (loc, true);
4477 _session->set_auto_loop_location (loc);
4478 XMLNode &after = _session->locations()->get_state();
4479 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4481 XMLNode &before = tll->get_state();
4482 tll->set_hidden (false, this);
4483 tll->set (start, end);
4484 XMLNode &after = tll->get_state();
4485 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4488 commit_reversible_command ();
4492 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4494 if (!_session) return;
4496 begin_reversible_command (cmd);
4500 if ((tpl = transport_punch_location()) == 0) {
4501 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4502 XMLNode &before = _session->locations()->get_state();
4503 _session->locations()->add (loc, true);
4504 _session->set_auto_loop_location (loc);
4505 XMLNode &after = _session->locations()->get_state();
4506 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4509 XMLNode &before = tpl->get_state();
4510 tpl->set_hidden (false, this);
4511 tpl->set (start, end);
4512 XMLNode &after = tpl->get_state();
4513 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4516 commit_reversible_command ();
4519 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4520 * @param rs List to which found regions are added.
4521 * @param where Time to look at.
4522 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4525 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4527 const TrackViewList* tracks;
4530 tracks = &track_views;
4535 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4537 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4540 boost::shared_ptr<Track> tr;
4541 boost::shared_ptr<Playlist> pl;
4543 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4545 boost::shared_ptr<RegionList> regions = pl->regions_at (
4546 (framepos_t) floor ( (double) where * tr->speed()));
4548 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4549 RegionView* rv = rtv->view()->find_view (*i);
4560 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4562 const TrackViewList* tracks;
4565 tracks = &track_views;
4570 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4571 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4573 boost::shared_ptr<Track> tr;
4574 boost::shared_ptr<Playlist> pl;
4576 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4578 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4579 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4581 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4583 RegionView* rv = rtv->view()->find_view (*i);
4594 /** Start with regions that are selected. Then add equivalent regions
4595 * on tracks in the same active edit-enabled route group as any of
4596 * the regions that we started with.
4600 Editor::get_regions_from_selection ()
4602 return get_equivalent_regions (selection->regions, ARDOUR::Properties::select.property_id);
4605 /** Get regions using the following method:
4607 * Make an initial region list using the selected regions, unless
4608 * the edit point is `mouse' and the mouse is over an unselected
4609 * region. In this case, start with just that region.
4611 * Then, add equivalent regions in active edit groups to the region list.
4613 * Then, search the list of selected tracks to find any selected tracks which
4614 * do not contain regions already in the region list. If there are no selected
4615 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4616 * than just the selected.
4618 * Add any regions that are under the edit point on these tracks to get the
4619 * returned region list.
4621 * The rationale here is that the mouse edit point is special in that
4622 * its position describes both a time and a track; the other edit
4623 * modes only describe a time. Hence if the edit point is `mouse' we
4624 * ignore selected tracks, as we assume the user means something by
4625 * pointing at a particular track. Also in this case we take note of
4626 * the region directly under the edit point, as there is always just one
4627 * (rather than possibly several with non-mouse edit points).
4631 Editor::get_regions_from_selection_and_edit_point ()
4633 RegionSelection regions;
4635 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4636 regions.add (entered_regionview);
4638 regions = selection->regions;
4641 TrackViewList tracks;
4643 if (_edit_point != EditAtMouse) {
4644 tracks = selection->tracks;
4647 /* Add any other regions that are in the same
4648 edit-activated route group as one of our regions.
4650 regions = get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4651 framepos_t const where = get_preferred_edit_position ();
4653 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4654 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4655 * is enabled, so consider all tracks
4657 tracks = track_views;
4660 if (!tracks.empty()) {
4661 /* now search the selected tracks for tracks which don't
4662 already contain regions to be acted upon, and get regions at
4663 the edit point on those tracks too.
4665 TrackViewList tracks_without_relevant_regions;
4667 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4668 if (!regions.involves (**t)) {
4669 /* there are no equivalent regions on this track */
4670 tracks_without_relevant_regions.push_back (*t);
4674 if (!tracks_without_relevant_regions.empty()) {
4675 /* there are some selected tracks with neither selected
4676 * regions or their equivalents: act upon all regions in
4679 get_regions_at (regions, where, tracks_without_relevant_regions);
4686 /** Start with regions that are selected, or the entered regionview if none are selected.
4687 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4688 * of the regions that we started with.
4692 Editor::get_regions_from_selection_and_entered ()
4694 RegionSelection regions = selection->regions;
4696 if (regions.empty() && entered_regionview) {
4697 regions.add (entered_regionview);
4700 return get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4704 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4706 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4708 RouteTimeAxisView* tatv;
4710 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4712 boost::shared_ptr<Playlist> pl;
4713 vector<boost::shared_ptr<Region> > results;
4715 boost::shared_ptr<Track> tr;
4717 if ((tr = tatv->track()) == 0) {
4722 if ((pl = (tr->playlist())) != 0) {
4723 if (src_comparison) {
4724 pl->get_source_equivalent_regions (region, results);
4726 pl->get_region_list_equivalent_regions (region, results);
4730 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4731 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4732 regions.push_back (marv);
4741 Editor::show_rhythm_ferret ()
4743 if (rhythm_ferret == 0) {
4744 rhythm_ferret = new RhythmFerret(*this);
4747 rhythm_ferret->set_session (_session);
4748 rhythm_ferret->show ();
4749 rhythm_ferret->present ();
4753 Editor::first_idle ()
4755 MessageDialog* dialog = 0;
4757 if (track_views.size() > 1) {
4758 dialog = new MessageDialog (
4760 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4764 ARDOUR_UI::instance()->flush_pending ();
4767 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4771 // first idle adds route children (automation tracks), so we need to redisplay here
4772 _routes->redisplay ();
4779 Editor::_idle_resize (gpointer arg)
4781 return ((Editor*)arg)->idle_resize ();
4785 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4787 if (resize_idle_id < 0) {
4788 resize_idle_id = g_idle_add (_idle_resize, this);
4789 _pending_resize_amount = 0;
4792 /* make a note of the smallest resulting height, so that we can clamp the
4793 lower limit at TimeAxisView::hSmall */
4795 int32_t min_resulting = INT32_MAX;
4797 _pending_resize_amount += h;
4798 _pending_resize_view = view;
4800 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4802 if (selection->tracks.contains (_pending_resize_view)) {
4803 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4804 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4808 if (min_resulting < 0) {
4813 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4814 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4818 /** Handle pending resizing of tracks */
4820 Editor::idle_resize ()
4822 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4824 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4825 selection->tracks.contains (_pending_resize_view)) {
4827 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4828 if (*i != _pending_resize_view) {
4829 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4834 _pending_resize_amount = 0;
4836 _group_tabs->set_dirty ();
4837 resize_idle_id = -1;
4845 ENSURE_GUI_THREAD (*this, &Editor::located);
4848 playhead_cursor->set_position (_session->audible_frame ());
4849 if (_follow_playhead && !_pending_initial_locate) {
4850 reset_x_origin_to_follow_playhead ();
4854 _pending_locate_request = false;
4855 _pending_initial_locate = false;
4859 Editor::region_view_added (RegionView *)
4861 _summary->set_dirty ();
4865 Editor::region_view_removed ()
4867 _summary->set_dirty ();
4871 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4873 TrackViewList::const_iterator j = track_views.begin ();
4874 while (j != track_views.end()) {
4875 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4876 if (rtv && rtv->route() == r) {
4887 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4891 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4892 TimeAxisView* tv = axis_view_from_route (*i);
4902 Editor::add_routes (RouteList& routes)
4904 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4906 RouteTimeAxisView *rtv;
4907 list<RouteTimeAxisView*> new_views;
4909 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4910 boost::shared_ptr<Route> route = (*x);
4912 if (route->is_hidden() || route->is_monitor()) {
4916 DataType dt = route->input()->default_type();
4918 if (dt == ARDOUR::DataType::AUDIO) {
4919 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4920 rtv->set_route (route);
4921 } else if (dt == ARDOUR::DataType::MIDI) {
4922 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4923 rtv->set_route (route);
4925 throw unknown_type();
4928 new_views.push_back (rtv);
4929 track_views.push_back (rtv);
4931 rtv->effective_gain_display ();
4933 if (internal_editing()) {
4934 rtv->enter_internal_edit_mode ();
4936 rtv->leave_internal_edit_mode ();
4939 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4940 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4943 _routes->routes_added (new_views);
4944 _summary->routes_added (new_views);
4946 if (show_editor_mixer_when_tracks_arrive) {
4947 show_editor_mixer (true);
4950 editor_list_button.set_sensitive (true);
4954 Editor::timeaxisview_deleted (TimeAxisView *tv)
4956 if (_session && _session->deletion_in_progress()) {
4957 /* the situation is under control */
4961 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4963 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4965 _routes->route_removed (tv);
4967 if (tv == entered_track) {
4971 TimeAxisView::Children c = tv->get_child_list ();
4972 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4973 if (entered_track == i->get()) {
4978 /* remove it from the list of track views */
4980 TrackViewList::iterator i;
4982 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4983 i = track_views.erase (i);
4986 /* update whatever the current mixer strip is displaying, if revelant */
4988 boost::shared_ptr<Route> route;
4991 route = rtav->route ();
4994 if (current_mixer_strip && current_mixer_strip->route() == route) {
4996 TimeAxisView* next_tv;
4998 if (track_views.empty()) {
5000 } else if (i == track_views.end()) {
5001 next_tv = track_views.front();
5008 set_selected_mixer_strip (*next_tv);
5010 /* make the editor mixer strip go away setting the
5011 * button to inactive (which also unticks the menu option)
5014 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5020 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5022 if (apply_to_selection) {
5023 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5025 TrackSelection::iterator j = i;
5028 hide_track_in_display (*i, false);
5033 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5035 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5036 // this will hide the mixer strip
5037 set_selected_mixer_strip (*tv);
5040 _routes->hide_track_in_display (*tv);
5045 Editor::sync_track_view_list_and_routes ()
5047 track_views = TrackViewList (_routes->views ());
5049 _summary->set_dirty ();
5050 _group_tabs->set_dirty ();
5052 return false; // do not call again (until needed)
5056 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5058 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5063 /** Find a RouteTimeAxisView by the ID of its route */
5065 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5067 RouteTimeAxisView* v;
5069 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5070 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5071 if(v->route()->id() == id) {
5081 Editor::fit_route_group (RouteGroup *g)
5083 TrackViewList ts = axis_views_from_routes (g->route_list ());
5088 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5090 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5093 _session->cancel_audition ();
5097 if (_session->is_auditioning()) {
5098 _session->cancel_audition ();
5099 if (r == last_audition_region) {
5104 _session->audition_region (r);
5105 last_audition_region = r;
5110 Editor::hide_a_region (boost::shared_ptr<Region> r)
5112 r->set_hidden (true);
5116 Editor::show_a_region (boost::shared_ptr<Region> r)
5118 r->set_hidden (false);
5122 Editor::audition_region_from_region_list ()
5124 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5128 Editor::hide_region_from_region_list ()
5130 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5134 Editor::show_region_in_region_list ()
5136 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5140 Editor::step_edit_status_change (bool yn)
5143 start_step_editing ();
5145 stop_step_editing ();
5150 Editor::start_step_editing ()
5152 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5156 Editor::stop_step_editing ()
5158 step_edit_connection.disconnect ();
5162 Editor::check_step_edit ()
5164 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5165 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5167 mtv->check_step_edit ();
5171 return true; // do it again, till we stop
5175 Editor::scroll_press (Direction dir)
5177 ++_scroll_callbacks;
5179 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5180 /* delay the first auto-repeat */
5186 scroll_backward (1);
5194 scroll_tracks_up_line ();
5198 scroll_tracks_down_line ();
5202 /* do hacky auto-repeat */
5203 if (!_scroll_connection.connected ()) {
5205 _scroll_connection = Glib::signal_timeout().connect (
5206 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5209 _scroll_callbacks = 0;
5216 Editor::scroll_release ()
5218 _scroll_connection.disconnect ();
5221 /** Queue a change for the Editor viewport x origin to follow the playhead */
5223 Editor::reset_x_origin_to_follow_playhead ()
5225 framepos_t const frame = playhead_cursor->current_frame ();
5227 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5229 if (_session->transport_speed() < 0) {
5231 if (frame > (current_page_frames() / 2)) {
5232 center_screen (frame-(current_page_frames()/2));
5234 center_screen (current_page_frames()/2);
5241 if (frame < leftmost_frame) {
5243 if (_session->transport_rolling()) {
5244 /* rolling; end up with the playhead at the right of the page */
5245 l = frame - current_page_frames ();
5247 /* not rolling: end up with the playhead 1/4 of the way along the page */
5248 l = frame - current_page_frames() / 4;
5252 if (_session->transport_rolling()) {
5253 /* rolling: end up with the playhead on the left of the page */
5256 /* not rolling: end up with the playhead 3/4 of the way along the page */
5257 l = frame - 3 * current_page_frames() / 4;
5265 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5271 Editor::super_rapid_screen_update ()
5273 if (!_session || !_session->engine().running()) {
5277 /* METERING / MIXER STRIPS */
5279 /* update track meters, if required */
5280 if (is_mapped() && meters_running) {
5281 RouteTimeAxisView* rtv;
5282 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5283 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5284 rtv->fast_update ();
5289 /* and any current mixer strip */
5290 if (current_mixer_strip) {
5291 current_mixer_strip->fast_update ();
5294 /* PLAYHEAD AND VIEWPORT */
5296 framepos_t const frame = _session->audible_frame();
5298 /* There are a few reasons why we might not update the playhead / viewport stuff:
5300 * 1. we don't update things when there's a pending locate request, otherwise
5301 * when the editor requests a locate there is a chance that this method
5302 * will move the playhead before the locate request is processed, causing
5304 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5305 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5308 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5310 last_update_frame = frame;
5312 if (!_dragging_playhead) {
5313 playhead_cursor->set_position (frame);
5316 if (!_stationary_playhead) {
5318 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5319 /* We only do this if we aren't already
5320 handling a visual change (ie if
5321 pending_visual_change.being_handled is
5322 false) so that these requests don't stack
5323 up there are too many of them to handle in
5326 reset_x_origin_to_follow_playhead ();
5331 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5335 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5336 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_pixel;
5337 if (target <= 0.0) {
5340 if (fabs(target - current) < current_page_frames() / frames_per_pixel) {
5341 target = (target * 0.15) + (current * 0.85);
5347 set_horizontal_position (current);
5356 Editor::session_going_away ()
5358 _have_idled = false;
5360 _session_connections.drop_connections ();
5362 super_rapid_screen_update_connection.disconnect ();
5364 selection->clear ();
5365 cut_buffer->clear ();
5367 clicked_regionview = 0;
5368 clicked_axisview = 0;
5369 clicked_routeview = 0;
5370 entered_regionview = 0;
5372 last_update_frame = 0;
5375 playhead_cursor->hide ();
5377 /* rip everything out of the list displays */
5381 _route_groups->clear ();
5383 /* do this first so that deleting a track doesn't reset cms to null
5384 and thus cause a leak.
5387 if (current_mixer_strip) {
5388 if (current_mixer_strip->get_parent() != 0) {
5389 global_hpacker.remove (*current_mixer_strip);
5391 delete current_mixer_strip;
5392 current_mixer_strip = 0;
5395 /* delete all trackviews */
5397 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5400 track_views.clear ();
5402 zoom_range_clock->set_session (0);
5403 nudge_clock->set_session (0);
5405 editor_list_button.set_active(false);
5406 editor_list_button.set_sensitive(false);
5408 /* clear tempo/meter rulers */
5409 remove_metric_marks ();
5411 clear_marker_display ();
5413 stop_step_editing ();
5415 /* get rid of any existing editor mixer strip */
5417 WindowTitle title(Glib::get_application_name());
5418 title += _("Editor");
5420 set_title (title.get_string());
5422 SessionHandlePtr::session_going_away ();
5427 Editor::show_editor_list (bool yn)
5430 _the_notebook.show ();
5432 _the_notebook.hide ();
5437 Editor::change_region_layering_order (bool from_context_menu)
5439 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5441 if (!clicked_routeview) {
5442 if (layering_order_editor) {
5443 layering_order_editor->hide ();
5448 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5454 boost::shared_ptr<Playlist> pl = track->playlist();
5460 if (layering_order_editor == 0) {
5461 layering_order_editor = new RegionLayeringOrderEditor (*this);
5462 layering_order_editor->set_position (WIN_POS_MOUSE);
5465 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5466 layering_order_editor->maybe_present ();
5470 Editor::update_region_layering_order_editor ()
5472 if (layering_order_editor && layering_order_editor->is_visible ()) {
5473 change_region_layering_order (true);
5478 Editor::setup_fade_images ()
5480 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5481 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5482 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5483 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5484 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5486 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5487 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5488 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5489 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5490 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5492 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5493 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5494 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5495 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5496 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5498 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5499 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5500 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5501 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5502 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5506 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5508 Editor::action_menu_item (std::string const & name)
5510 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5513 return *manage (a->create_menu_item ());
5517 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5519 EventBox* b = manage (new EventBox);
5520 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5521 Label* l = manage (new Label (name));
5525 _the_notebook.append_page (widget, *b);
5529 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5531 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5532 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5535 if (ev->type == GDK_2BUTTON_PRESS) {
5537 /* double-click on a notebook tab shrinks or expands the notebook */
5539 if (_notebook_shrunk) {
5540 if (pre_notebook_shrink_pane_width) {
5541 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5543 _notebook_shrunk = false;
5545 pre_notebook_shrink_pane_width = edit_pane.get_position();
5547 /* this expands the LHS of the edit pane to cover the notebook
5548 PAGE but leaves the tabs visible.
5550 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5551 _notebook_shrunk = true;
5559 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5561 using namespace Menu_Helpers;
5563 MenuList& items = _control_point_context_menu.items ();
5566 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5567 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5568 if (!can_remove_control_point (item)) {
5569 items.back().set_sensitive (false);
5572 _control_point_context_menu.popup (event->button.button, event->button.time);
5576 Editor::shift_key_released ()
5578 _stepping_axis_view = 0;
5583 Editor::save_canvas_state ()
5585 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5586 string path = string_compose ("%1/canvas-state.xml", _session->path());