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::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
501 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
502 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
503 pad_line_1->set_outline_color (0xFF0000FF);
509 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
510 time_canvas_vbox.set_size_request (-1, -1);
512 ruler_label_event_box.add (ruler_label_vbox);
513 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 time_bars_event_box.add (time_bars_vbox);
517 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
518 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
520 /* these enable us to have a dedicated window (for cursor setting, etc.)
521 for the canvas areas.
524 track_canvas_event_box.add (*_track_canvas_viewport);
526 time_canvas_event_box.add (time_canvas_vbox);
527 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
529 edit_packer.set_col_spacings (0);
530 edit_packer.set_row_spacings (0);
531 edit_packer.set_homogeneous (false);
532 edit_packer.set_border_width (0);
533 edit_packer.set_name ("EditorWindow");
535 /* labels for the rulers */
536 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
537 /* labels for the marker "tracks" (time bars) */
538 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
540 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
542 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
543 /* time bars canvas */
544 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
546 edit_packer.attach (track_canvas_event_box, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
548 bottom_hbox.set_border_width (2);
549 bottom_hbox.set_spacing (3);
551 _route_groups = new EditorRouteGroups (this);
552 _routes = new EditorRoutes (this);
553 _regions = new EditorRegions (this);
554 _snapshots = new EditorSnapshots (this);
555 _locations = new EditorLocations (this);
557 add_notebook_page (_("Regions"), _regions->widget ());
558 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
559 add_notebook_page (_("Snapshots"), _snapshots->widget ());
560 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
561 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
563 _the_notebook.set_show_tabs (true);
564 _the_notebook.set_scrollable (true);
565 _the_notebook.popup_disable ();
566 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
567 _the_notebook.show_all ();
569 _notebook_shrunk = false;
571 editor_summary_pane.pack1(edit_packer);
573 Button* summary_arrows_left_left = manage (new Button);
574 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
575 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
576 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_left_right = manage (new Button);
579 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
580 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
581 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_left = manage (new VBox);
584 summary_arrows_left->pack_start (*summary_arrows_left_left);
585 summary_arrows_left->pack_start (*summary_arrows_left_right);
587 Button* summary_arrows_right_up = manage (new Button);
588 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
589 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
590 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 Button* summary_arrows_right_down = manage (new Button);
593 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
594 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
595 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 VBox* summary_arrows_right = manage (new VBox);
598 summary_arrows_right->pack_start (*summary_arrows_right_up);
599 summary_arrows_right->pack_start (*summary_arrows_right_down);
601 Frame* summary_frame = manage (new Frame);
602 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
604 summary_frame->add (*_summary);
605 summary_frame->show ();
607 _summary_hbox.pack_start (*summary_arrows_left, false, false);
608 _summary_hbox.pack_start (*summary_frame, true, true);
609 _summary_hbox.pack_start (*summary_arrows_right, false, false);
611 editor_summary_pane.pack2 (_summary_hbox);
613 edit_pane.pack1 (editor_summary_pane, true, true);
614 edit_pane.pack2 (_the_notebook, false, true);
616 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
618 /* XXX: editor_summary_pane might need similar to the edit_pane */
620 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
622 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
623 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
625 top_hbox.pack_start (toolbar_frame);
627 HBox *hbox = manage (new HBox);
628 hbox->pack_start (edit_pane, true, true);
630 global_vpacker.pack_start (top_hbox, false, false);
631 global_vpacker.pack_start (*hbox, true, true);
633 global_hpacker.pack_start (global_vpacker, true, true);
635 set_name ("EditorWindow");
636 add_accel_group (ActionManager::ui_manager->get_accel_group());
638 status_bar_hpacker.show ();
640 vpacker.pack_end (status_bar_hpacker, false, false);
641 vpacker.pack_end (global_hpacker, true, true);
643 /* register actions now so that set_state() can find them and set toggles/checks etc */
646 /* when we start using our own keybinding system for the editor, this
647 * will be uncommented
653 _snap_type = SnapToBeat;
654 set_snap_to (_snap_type);
655 _snap_mode = SnapOff;
656 set_snap_mode (_snap_mode);
657 set_mouse_mode (MouseObject, true);
658 pre_internal_mouse_mode = MouseObject;
659 pre_internal_snap_type = _snap_type;
660 pre_internal_snap_mode = _snap_mode;
661 internal_snap_type = _snap_type;
662 internal_snap_mode = _snap_mode;
663 set_edit_point_preference (EditAtMouse, true);
665 _playlist_selector = new PlaylistSelector();
666 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
668 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
672 nudge_forward_button.set_name ("zoom button");
673 nudge_forward_button.add_elements (ArdourButton::FlatFace);
674 nudge_forward_button.set_image(::get_icon("nudge_right"));
676 nudge_backward_button.set_name ("zoom button");
677 nudge_backward_button.add_elements (ArdourButton::FlatFace);
678 nudge_backward_button.set_image(::get_icon("nudge_left"));
680 fade_context_menu.set_name ("ArdourContextMenu");
682 /* icons, titles, WM stuff */
684 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
685 Glib::RefPtr<Gdk::Pixbuf> icon;
687 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
688 window_icons.push_back (icon);
690 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
691 window_icons.push_back (icon);
693 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
694 window_icons.push_back (icon);
696 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
697 window_icons.push_back (icon);
699 if (!window_icons.empty()) {
700 // set_icon_list (window_icons);
701 set_default_icon_list (window_icons);
704 WindowTitle title(Glib::get_application_name());
705 title += _("Editor");
706 set_title (title.get_string());
707 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
710 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
712 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
713 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
715 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
717 /* allow external control surfaces/protocols to do various things */
719 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
720 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
721 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
722 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
723 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
724 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
725 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
726 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
727 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
728 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
729 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
730 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
731 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
732 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
734 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
735 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
736 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
737 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
738 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
740 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
742 /* problematic: has to return a value and thus cannot be x-thread */
744 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
746 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
748 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
750 _ignore_region_action = false;
751 _last_region_menu_was_main = false;
752 _popup_region_menu_item = 0;
754 _show_marker_lines = false;
755 _over_region_trim_target = false;
757 /* Button bindings */
759 button_bindings = new Bindings;
761 XMLNode* node = button_settings();
763 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
764 button_bindings->load (**i);
771 setup_fade_images ();
777 if(image_socket_listener) {
778 if(image_socket_listener->is_connected())
780 image_socket_listener->close_connection() ;
783 delete image_socket_listener ;
784 image_socket_listener = 0 ;
788 delete button_bindings;
790 delete _route_groups;
791 delete _track_canvas_viewport;
796 Editor::button_settings () const
798 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
799 XMLNode* node = find_named_node (*settings, X_("Buttons"));
802 node = new XMLNode (X_("Buttons"));
809 Editor::add_toplevel_controls (Container& cont)
811 vpacker.pack_start (cont, false, false);
816 Editor::get_smart_mode () const
818 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
822 Editor::catch_vanishing_regionview (RegionView *rv)
824 /* note: the selection will take care of the vanishing
825 audioregionview by itself.
828 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
832 if (clicked_regionview == rv) {
833 clicked_regionview = 0;
836 if (entered_regionview == rv) {
837 set_entered_regionview (0);
840 if (!_all_region_actions_sensitized) {
841 sensitize_all_region_actions (true);
844 _over_region_trim_target = false;
848 Editor::set_entered_regionview (RegionView* rv)
850 if (rv == entered_regionview) {
854 if (entered_regionview) {
855 entered_regionview->exited ();
858 if ((entered_regionview = rv) != 0) {
859 entered_regionview->entered (internal_editing ());
862 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
863 /* This RegionView entry might have changed what region actions
864 are allowed, so sensitize them all in case a key is pressed.
866 sensitize_all_region_actions (true);
871 Editor::set_entered_track (TimeAxisView* tav)
874 entered_track->exited ();
877 if ((entered_track = tav) != 0) {
878 entered_track->entered ();
883 Editor::show_window ()
885 if (!is_visible ()) {
888 /* XXX: this is a bit unfortunate; it would probably
889 be nicer if we could just call show () above rather
890 than needing the show_all ()
893 /* re-hide stuff if necessary */
894 editor_list_button_toggled ();
895 parameter_changed ("show-summary");
896 parameter_changed ("show-group-tabs");
897 parameter_changed ("show-zoom-tools");
899 /* now reset all audio_time_axis heights, because widgets might need
905 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
906 tv = (static_cast<TimeAxisView*>(*i));
910 if (current_mixer_strip) {
911 current_mixer_strip->hide_things ();
912 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
920 Editor::instant_save ()
922 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
927 _session->add_instant_xml(get_state());
929 Config->add_instant_xml(get_state());
934 Editor::zoom_adjustment_changed ()
940 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
941 bool clamped = clamp_frames_per_pixel (fpu);
944 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
951 Editor::control_vertical_zoom_in_all ()
953 tav_zoom_smooth (false, true);
957 Editor::control_vertical_zoom_out_all ()
959 tav_zoom_smooth (true, true);
963 Editor::control_vertical_zoom_in_selected ()
965 tav_zoom_smooth (false, false);
969 Editor::control_vertical_zoom_out_selected ()
971 tav_zoom_smooth (true, false);
975 Editor::control_view (uint32_t view)
977 goto_visual_state (view);
981 Editor::control_unselect ()
983 selection->clear_tracks ();
987 Editor::control_select (uint32_t rid, Selection::Operation op)
989 /* handles the (static) signal from the ControlProtocol class that
990 * requests setting the selected track to a given RID
997 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1003 TimeAxisView* tav = axis_view_from_route (r);
1007 case Selection::Add:
1008 selection->add (tav);
1010 case Selection::Toggle:
1011 selection->toggle (tav);
1013 case Selection::Extend:
1015 case Selection::Set:
1016 selection->set (tav);
1020 selection->clear_tracks ();
1025 Editor::control_step_tracks_up ()
1027 scroll_tracks_up_line ();
1031 Editor::control_step_tracks_down ()
1033 scroll_tracks_down_line ();
1037 Editor::control_scroll (float fraction)
1039 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1045 double step = fraction * current_page_frames();
1048 _control_scroll_target is an optional<T>
1050 it acts like a pointer to an framepos_t, with
1051 a operator conversion to boolean to check
1052 that it has a value could possibly use
1053 playhead_cursor->current_frame to store the
1054 value and a boolean in the class to know
1055 when it's out of date
1058 if (!_control_scroll_target) {
1059 _control_scroll_target = _session->transport_frame();
1060 _dragging_playhead = true;
1063 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1064 *_control_scroll_target = 0;
1065 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1066 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1068 *_control_scroll_target += (framepos_t) floor (step);
1071 /* move visuals, we'll catch up with it later */
1073 playhead_cursor->set_position (*_control_scroll_target);
1074 UpdateAllTransportClocks (*_control_scroll_target);
1076 if (*_control_scroll_target > (current_page_frames() / 2)) {
1077 /* try to center PH in window */
1078 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1084 Now we do a timeout to actually bring the session to the right place
1085 according to the playhead. This is to avoid reading disk buffers on every
1086 call to control_scroll, which is driven by ScrollTimeline and therefore
1087 probably by a control surface wheel which can generate lots of events.
1089 /* cancel the existing timeout */
1091 control_scroll_connection.disconnect ();
1093 /* add the next timeout */
1095 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1099 Editor::deferred_control_scroll (framepos_t /*target*/)
1101 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1102 // reset for next stream
1103 _control_scroll_target = boost::none;
1104 _dragging_playhead = false;
1109 Editor::access_action (std::string action_group, std::string action_item)
1115 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1118 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1126 Editor::on_realize ()
1128 Window::on_realize ();
1133 Editor::map_position_change (framepos_t frame)
1135 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1137 if (_session == 0) {
1141 if (_follow_playhead) {
1142 center_screen (frame);
1145 playhead_cursor->set_position (frame);
1149 Editor::center_screen (framepos_t frame)
1151 double const page = _visible_canvas_width * frames_per_pixel;
1153 /* if we're off the page, then scroll.
1156 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1157 center_screen_internal (frame, page);
1162 Editor::center_screen_internal (framepos_t frame, float page)
1167 frame -= (framepos_t) page;
1172 reset_x_origin (frame);
1177 Editor::update_title ()
1179 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1182 bool dirty = _session->dirty();
1184 string session_name;
1186 if (_session->snap_name() != _session->name()) {
1187 session_name = _session->snap_name();
1189 session_name = _session->name();
1193 session_name = "*" + session_name;
1196 WindowTitle title(session_name);
1197 title += Glib::get_application_name();
1198 set_title (title.get_string());
1200 /* ::session_going_away() will have taken care of it */
1205 Editor::set_session (Session *t)
1207 SessionHandlePtr::set_session (t);
1213 zoom_range_clock->set_session (_session);
1214 _playlist_selector->set_session (_session);
1215 nudge_clock->set_session (_session);
1216 _summary->set_session (_session);
1217 _group_tabs->set_session (_session);
1218 _route_groups->set_session (_session);
1219 _regions->set_session (_session);
1220 _snapshots->set_session (_session);
1221 _routes->set_session (_session);
1222 _locations->set_session (_session);
1224 if (rhythm_ferret) {
1225 rhythm_ferret->set_session (_session);
1228 if (analysis_window) {
1229 analysis_window->set_session (_session);
1233 sfbrowser->set_session (_session);
1236 compute_fixed_ruler_scale ();
1238 /* Make sure we have auto loop and auto punch ranges */
1240 Location* loc = _session->locations()->auto_loop_location();
1242 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1244 if (loc->start() == loc->end()) {
1245 loc->set_end (loc->start() + 1);
1248 _session->locations()->add (loc, false);
1249 _session->set_auto_loop_location (loc);
1252 loc->set_name (_("Loop"));
1255 loc = _session->locations()->auto_punch_location();
1258 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1260 if (loc->start() == loc->end()) {
1261 loc->set_end (loc->start() + 1);
1264 _session->locations()->add (loc, false);
1265 _session->set_auto_punch_location (loc);
1268 loc->set_name (_("Punch"));
1271 refresh_location_display ();
1273 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1274 the selected Marker; this needs the LocationMarker list to be available.
1276 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1277 set_state (*node, Stateful::loading_state_version);
1279 /* catch up with the playhead */
1281 _session->request_locate (playhead_cursor->current_frame ());
1282 _pending_initial_locate = true;
1286 /* These signals can all be emitted by a non-GUI thread. Therefore the
1287 handlers for them must not attempt to directly interact with the GUI,
1288 but use Gtkmm2ext::UI::instance()->call_slot();
1291 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1292 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1293 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1294 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1295 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1296 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1297 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1298 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1299 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1300 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1301 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1302 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1303 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1304 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1306 playhead_cursor->show ();
1308 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1309 Config->map_parameters (pc);
1310 _session->config.map_parameters (pc);
1312 restore_ruler_visibility ();
1313 //tempo_map_changed (PropertyChange (0));
1314 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1316 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1317 (static_cast<TimeAxisView*>(*i))->set_frames_per_pixel (frames_per_pixel);
1320 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1321 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1324 switch (_snap_type) {
1325 case SnapToRegionStart:
1326 case SnapToRegionEnd:
1327 case SnapToRegionSync:
1328 case SnapToRegionBoundary:
1329 build_region_boundary_cache ();
1336 /* register for undo history */
1337 _session->register_with_memento_command_factory(id(), this);
1339 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1341 start_updating_meters ();
1345 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1347 if (a->get_name() == "RegionMenu") {
1348 /* When the main menu's region menu is opened, we setup the actions so that they look right
1349 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1350 so we resensitize all region actions when the entered regionview or the region selection
1351 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1352 happens after the region context menu is opened. So we set a flag here, too.
1356 sensitize_the_right_region_actions ();
1357 _last_region_menu_was_main = true;
1362 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1364 using namespace Menu_Helpers;
1366 void (Editor::*emf)(FadeShape);
1367 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1370 images = &_xfade_in_images;
1371 emf = &Editor::set_fade_in_shape;
1373 images = &_xfade_out_images;
1374 emf = &Editor::set_fade_out_shape;
1379 _("Linear (for highly correlated material)"),
1380 *(*images)[FadeLinear],
1381 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1389 _("Constant power"),
1390 *(*images)[FadeConstantPower],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *(*images)[FadeSymmetric],
1400 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *(*images)[FadeSlow],
1410 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 *(*images)[FadeFast],
1419 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1422 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1425 /** Pop up a context menu for when the user clicks on a start crossfade */
1427 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1429 using namespace Menu_Helpers;
1431 MenuList& items (xfade_in_context_menu.items());
1433 if (items.empty()) {
1434 fill_xfade_menu (items, true);
1437 xfade_in_context_menu.popup (button, time);
1440 /** Pop up a context menu for when the user clicks on an end crossfade */
1442 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1444 using namespace Menu_Helpers;
1446 MenuList& items (xfade_out_context_menu.items());
1448 if (items.empty()) {
1449 fill_xfade_menu (items, false);
1452 xfade_out_context_menu.popup (button, time);
1456 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1458 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1460 using namespace Menu_Helpers;
1461 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1464 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1468 MenuList& items (fade_context_menu.items());
1471 switch (item_type) {
1473 case FadeInHandleItem:
1474 if (arv->audio_region()->fade_in_active()) {
1475 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1477 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1480 items.push_back (SeparatorElem());
1482 if (Profile->get_sae()) {
1484 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1485 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1492 *_fade_in_images[FadeLinear],
1493 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *_fade_in_images[FadeSlow],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 *_fade_in_images[FadeFast],
1512 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 *_fade_in_images[FadeSymmetric],
1521 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1526 _("Constant power"),
1527 *_fade_in_images[FadeConstantPower],
1528 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1531 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1537 case FadeOutHandleItem:
1538 if (arv->audio_region()->fade_out_active()) {
1539 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1541 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1544 items.push_back (SeparatorElem());
1546 if (Profile->get_sae()) {
1547 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1548 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1554 *_fade_out_images[FadeLinear],
1555 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1559 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1564 *_fade_out_images[FadeSlow],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1568 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1573 *_fade_out_images[FadeFast],
1574 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1577 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1582 *_fade_out_images[FadeSymmetric],
1583 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1588 _("Constant power"),
1589 *_fade_out_images[FadeConstantPower],
1590 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1593 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1599 fatal << _("programming error: ")
1600 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1605 fade_context_menu.popup (button, time);
1609 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1611 using namespace Menu_Helpers;
1612 Menu* (Editor::*build_menu_function)();
1615 switch (item_type) {
1617 case RegionViewName:
1618 case RegionViewNameHighlight:
1619 case LeftFrameHandle:
1620 case RightFrameHandle:
1621 if (with_selection) {
1622 build_menu_function = &Editor::build_track_selection_context_menu;
1624 build_menu_function = &Editor::build_track_region_context_menu;
1629 if (with_selection) {
1630 build_menu_function = &Editor::build_track_selection_context_menu;
1632 build_menu_function = &Editor::build_track_context_menu;
1637 if (clicked_routeview->track()) {
1638 build_menu_function = &Editor::build_track_context_menu;
1640 build_menu_function = &Editor::build_track_bus_context_menu;
1645 /* probably shouldn't happen but if it does, we don't care */
1649 menu = (this->*build_menu_function)();
1650 menu->set_name ("ArdourContextMenu");
1652 /* now handle specific situations */
1654 switch (item_type) {
1656 case RegionViewName:
1657 case RegionViewNameHighlight:
1658 case LeftFrameHandle:
1659 case RightFrameHandle:
1660 if (!with_selection) {
1661 if (region_edit_menu_split_item) {
1662 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1663 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1665 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1668 if (region_edit_menu_split_multichannel_item) {
1669 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1670 region_edit_menu_split_multichannel_item->set_sensitive (true);
1672 region_edit_menu_split_multichannel_item->set_sensitive (false);
1685 /* probably shouldn't happen but if it does, we don't care */
1689 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1691 /* Bounce to disk */
1693 using namespace Menu_Helpers;
1694 MenuList& edit_items = menu->items();
1696 edit_items.push_back (SeparatorElem());
1698 switch (clicked_routeview->audio_track()->freeze_state()) {
1699 case AudioTrack::NoFreeze:
1700 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1703 case AudioTrack::Frozen:
1704 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1707 case AudioTrack::UnFrozen:
1708 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1714 if (item_type == StreamItem && clicked_routeview) {
1715 clicked_routeview->build_underlay_menu(menu);
1718 /* When the region menu is opened, we setup the actions so that they look right
1721 sensitize_the_right_region_actions ();
1722 _last_region_menu_was_main = false;
1724 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1725 menu->popup (button, time);
1729 Editor::build_track_context_menu ()
1731 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_context_menu.items();
1736 add_dstream_context_items (edit_items);
1737 return &track_context_menu;
1741 Editor::build_track_bus_context_menu ()
1743 using namespace Menu_Helpers;
1745 MenuList& edit_items = track_context_menu.items();
1748 add_bus_context_items (edit_items);
1749 return &track_context_menu;
1753 Editor::build_track_region_context_menu ()
1755 using namespace Menu_Helpers;
1756 MenuList& edit_items = track_region_context_menu.items();
1759 /* we've just cleared the track region context menu, so the menu that these
1760 two items were on will have disappeared; stop them dangling.
1762 region_edit_menu_split_item = 0;
1763 region_edit_menu_split_multichannel_item = 0;
1765 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1768 boost::shared_ptr<Track> tr;
1769 boost::shared_ptr<Playlist> pl;
1771 if ((tr = rtv->track())) {
1772 add_region_context_items (edit_items, tr);
1776 add_dstream_context_items (edit_items);
1778 return &track_region_context_menu;
1782 Editor::analyze_region_selection ()
1784 if (analysis_window == 0) {
1785 analysis_window = new AnalysisWindow();
1788 analysis_window->set_session(_session);
1790 analysis_window->show_all();
1793 analysis_window->set_regionmode();
1794 analysis_window->analyze();
1796 analysis_window->present();
1800 Editor::analyze_range_selection()
1802 if (analysis_window == 0) {
1803 analysis_window = new AnalysisWindow();
1806 analysis_window->set_session(_session);
1808 analysis_window->show_all();
1811 analysis_window->set_rangemode();
1812 analysis_window->analyze();
1814 analysis_window->present();
1818 Editor::build_track_selection_context_menu ()
1820 using namespace Menu_Helpers;
1821 MenuList& edit_items = track_selection_context_menu.items();
1822 edit_items.clear ();
1824 add_selection_context_items (edit_items);
1825 // edit_items.push_back (SeparatorElem());
1826 // add_dstream_context_items (edit_items);
1828 return &track_selection_context_menu;
1832 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1834 using namespace Menu_Helpers;
1836 /* OK, stick the region submenu at the top of the list, and then add
1840 RegionSelection rs = get_regions_from_selection_and_entered ();
1842 string::size_type pos = 0;
1843 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1845 /* we have to hack up the region name because "_" has a special
1846 meaning for menu titles.
1849 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1850 menu_item_name.replace (pos, 1, "__");
1854 if (_popup_region_menu_item == 0) {
1855 _popup_region_menu_item = new MenuItem (menu_item_name);
1856 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1857 _popup_region_menu_item->show ();
1859 _popup_region_menu_item->set_label (menu_item_name);
1862 const framepos_t position = get_preferred_edit_position (false, true);
1864 edit_items.push_back (*_popup_region_menu_item);
1865 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1866 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1868 edit_items.push_back (SeparatorElem());
1871 /** Add context menu items relevant to selection ranges.
1872 * @param edit_items List to add the items to.
1875 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1877 using namespace Menu_Helpers;
1879 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1880 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1885 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (
1889 _("Move Range Start to Previous Region Boundary"),
1890 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1894 edit_items.push_back (
1896 _("Move Range Start to Next Region Boundary"),
1897 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1901 edit_items.push_back (
1903 _("Move Range End to Previous Region Boundary"),
1904 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1908 edit_items.push_back (
1910 _("Move Range End to Next Region Boundary"),
1911 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1917 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1919 edit_items.push_back (SeparatorElem());
1920 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1922 edit_items.push_back (SeparatorElem());
1923 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1924 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1926 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1931 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1932 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1936 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1937 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1938 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1939 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1944 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1950 Menu *play_menu = manage (new Menu);
1951 MenuList& play_items = play_menu->items();
1952 play_menu->set_name ("ArdourContextMenu");
1954 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1955 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1956 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1957 play_items.push_back (SeparatorElem());
1958 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1960 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1964 Menu *select_menu = manage (new Menu);
1965 MenuList& select_items = select_menu->items();
1966 select_menu->set_name ("ArdourContextMenu");
1968 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1969 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1970 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1971 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1972 select_items.push_back (SeparatorElem());
1973 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1974 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1975 select_items.push_back (SeparatorElem());
1976 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1977 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1978 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1979 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1980 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1981 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1982 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1984 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1988 Menu *cutnpaste_menu = manage (new Menu);
1989 MenuList& cutnpaste_items = cutnpaste_menu->items();
1990 cutnpaste_menu->set_name ("ArdourContextMenu");
1992 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1993 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1994 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1996 cutnpaste_items.push_back (SeparatorElem());
1998 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1999 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2001 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2003 /* Adding new material */
2005 edit_items.push_back (SeparatorElem());
2006 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2007 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2027 using namespace Menu_Helpers;
2031 Menu *play_menu = manage (new Menu);
2032 MenuList& play_items = play_menu->items();
2033 play_menu->set_name ("ArdourContextMenu");
2035 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2036 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2037 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2041 Menu *select_menu = manage (new Menu);
2042 MenuList& select_items = select_menu->items();
2043 select_menu->set_name ("ArdourContextMenu");
2045 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2046 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2047 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2048 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2049 select_items.push_back (SeparatorElem());
2050 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2051 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2052 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2053 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2055 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2059 Menu *cutnpaste_menu = manage (new Menu);
2060 MenuList& cutnpaste_items = cutnpaste_menu->items();
2061 cutnpaste_menu->set_name ("ArdourContextMenu");
2063 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2064 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2065 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2081 Editor::snap_type() const
2087 Editor::snap_mode() const
2093 Editor::set_snap_to (SnapType st)
2095 unsigned int snap_ind = (unsigned int)st;
2099 if (snap_ind > snap_type_strings.size() - 1) {
2101 _snap_type = (SnapType)snap_ind;
2104 string str = snap_type_strings[snap_ind];
2106 if (str != snap_type_selector.get_active_text()) {
2107 snap_type_selector.set_active_text (str);
2112 switch (_snap_type) {
2113 case SnapToBeatDiv128:
2114 case SnapToBeatDiv64:
2115 case SnapToBeatDiv32:
2116 case SnapToBeatDiv28:
2117 case SnapToBeatDiv24:
2118 case SnapToBeatDiv20:
2119 case SnapToBeatDiv16:
2120 case SnapToBeatDiv14:
2121 case SnapToBeatDiv12:
2122 case SnapToBeatDiv10:
2123 case SnapToBeatDiv8:
2124 case SnapToBeatDiv7:
2125 case SnapToBeatDiv6:
2126 case SnapToBeatDiv5:
2127 case SnapToBeatDiv4:
2128 case SnapToBeatDiv3:
2129 case SnapToBeatDiv2: {
2130 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2131 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2133 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2134 current_bbt_points_begin, current_bbt_points_end);
2135 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2136 current_bbt_points_begin, current_bbt_points_end);
2137 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2141 case SnapToRegionStart:
2142 case SnapToRegionEnd:
2143 case SnapToRegionSync:
2144 case SnapToRegionBoundary:
2145 build_region_boundary_cache ();
2153 SnapChanged (); /* EMIT SIGNAL */
2157 Editor::set_snap_mode (SnapMode mode)
2159 string str = snap_mode_strings[(int)mode];
2161 if (_internal_editing) {
2162 internal_snap_mode = mode;
2164 pre_internal_snap_mode = mode;
2169 if (str != snap_mode_selector.get_active_text ()) {
2170 snap_mode_selector.set_active_text (str);
2176 Editor::set_edit_point_preference (EditPoint ep, bool force)
2178 bool changed = (_edit_point != ep);
2181 string str = edit_point_strings[(int)ep];
2183 if (str != edit_point_selector.get_active_text ()) {
2184 edit_point_selector.set_active_text (str);
2187 set_canvas_cursor ();
2189 if (!force && !changed) {
2193 const char* action=NULL;
2195 switch (_edit_point) {
2196 case EditAtPlayhead:
2197 action = "edit-at-playhead";
2199 case EditAtSelectedMarker:
2200 action = "edit-at-marker";
2203 action = "edit-at-mouse";
2207 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2209 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2213 bool in_track_canvas;
2215 if (!mouse_frame (foo, in_track_canvas)) {
2216 in_track_canvas = false;
2219 reset_canvas_action_sensitivity (in_track_canvas);
2225 Editor::set_state (const XMLNode& node, int /*version*/)
2227 const XMLProperty* prop;
2234 g.base_width = default_width;
2235 g.base_height = default_height;
2239 if ((geometry = find_named_node (node, "geometry")) != 0) {
2243 if ((prop = geometry->property("x_size")) == 0) {
2244 prop = geometry->property ("x-size");
2247 g.base_width = atoi(prop->value());
2249 if ((prop = geometry->property("y_size")) == 0) {
2250 prop = geometry->property ("y-size");
2253 g.base_height = atoi(prop->value());
2256 if ((prop = geometry->property ("x_pos")) == 0) {
2257 prop = geometry->property ("x-pos");
2260 x = atoi (prop->value());
2263 if ((prop = geometry->property ("y_pos")) == 0) {
2264 prop = geometry->property ("y-pos");
2267 y = atoi (prop->value());
2271 set_default_size (g.base_width, g.base_height);
2274 if (_session && (prop = node.property ("playhead"))) {
2276 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2277 playhead_cursor->set_position (pos);
2279 playhead_cursor->set_position (0);
2282 if ((prop = node.property ("mixer-width"))) {
2283 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2286 if ((prop = node.property ("zoom-focus"))) {
2287 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2290 if ((prop = node.property ("zoom"))) {
2291 reset_zoom (PBD::atof (prop->value()));
2293 reset_zoom (frames_per_pixel);
2296 if ((prop = node.property ("snap-to"))) {
2297 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2300 if ((prop = node.property ("snap-mode"))) {
2301 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2304 if ((prop = node.property ("internal-snap-to"))) {
2305 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2308 if ((prop = node.property ("internal-snap-mode"))) {
2309 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2312 if ((prop = node.property ("pre-internal-snap-to"))) {
2313 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2317 if ((prop = node.property ("pre-internal-snap-mode"))) {
2318 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2321 if ((prop = node.property ("mouse-mode"))) {
2322 MouseMode m = str2mousemode(prop->value());
2323 set_mouse_mode (m, true);
2325 set_mouse_mode (MouseObject, true);
2328 if ((prop = node.property ("left-frame")) != 0) {
2330 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2334 reset_x_origin (pos);
2338 if ((prop = node.property ("y-origin")) != 0) {
2339 reset_y_origin (atof (prop->value ()));
2342 if ((prop = node.property ("internal-edit"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2346 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2347 tact->set_active (!yn);
2348 tact->set_active (yn);
2352 if ((prop = node.property ("join-object-range"))) {
2353 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2354 bool yn = string_is_affirmative (prop->value());
2356 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2357 tact->set_active (!yn);
2358 tact->set_active (yn);
2360 set_mouse_mode(mouse_mode, true);
2363 if ((prop = node.property ("edit-point"))) {
2364 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2367 if ((prop = node.property ("show-measures"))) {
2368 bool yn = string_is_affirmative (prop->value());
2369 _show_measures = yn;
2370 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2372 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2373 /* do it twice to force the change */
2374 tact->set_active (!yn);
2375 tact->set_active (yn);
2379 if ((prop = node.property ("follow-playhead"))) {
2380 bool yn = string_is_affirmative (prop->value());
2381 set_follow_playhead (yn);
2382 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2384 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2385 if (tact->get_active() != yn) {
2386 tact->set_active (yn);
2391 if ((prop = node.property ("stationary-playhead"))) {
2392 bool yn = string_is_affirmative (prop->value());
2393 set_stationary_playhead (yn);
2394 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2396 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2397 if (tact->get_active() != yn) {
2398 tact->set_active (yn);
2403 if ((prop = node.property ("region-list-sort-type"))) {
2404 RegionListSortType st;
2405 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2408 if ((prop = node.property ("show-editor-mixer"))) {
2410 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2413 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2414 bool yn = string_is_affirmative (prop->value());
2416 /* do it twice to force the change */
2418 tact->set_active (!yn);
2419 tact->set_active (yn);
2422 if ((prop = node.property ("show-editor-list"))) {
2424 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2427 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2428 bool yn = string_is_affirmative (prop->value());
2430 /* do it twice to force the change */
2432 tact->set_active (!yn);
2433 tact->set_active (yn);
2436 if ((prop = node.property (X_("editor-list-page")))) {
2437 _the_notebook.set_current_page (atoi (prop->value ()));
2440 if ((prop = node.property (X_("show-marker-lines")))) {
2441 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2443 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2444 bool yn = string_is_affirmative (prop->value ());
2446 tact->set_active (!yn);
2447 tact->set_active (yn);
2450 XMLNodeList children = node.children ();
2451 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2452 selection->set_state (**i, Stateful::current_state_version);
2453 _regions->set_state (**i);
2456 if ((prop = node.property ("maximised"))) {
2457 bool yn = string_is_affirmative (prop->value());
2459 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2463 if ((prop = node.property ("nudge-clock-value"))) {
2465 sscanf (prop->value().c_str(), "%" PRId64, &f);
2466 nudge_clock->set (f);
2468 nudge_clock->set_mode (AudioClock::Timecode);
2469 nudge_clock->set (_session->frame_rate() * 5, true);
2476 Editor::get_state ()
2478 XMLNode* node = new XMLNode ("Editor");
2481 id().print (buf, sizeof (buf));
2482 node->add_property ("id", buf);
2484 if (is_realized()) {
2485 Glib::RefPtr<Gdk::Window> win = get_window();
2487 int x, y, width, height;
2488 win->get_root_origin(x, y);
2489 win->get_size(width, height);
2491 XMLNode* geometry = new XMLNode ("geometry");
2493 snprintf(buf, sizeof(buf), "%d", width);
2494 geometry->add_property("x-size", string(buf));
2495 snprintf(buf, sizeof(buf), "%d", height);
2496 geometry->add_property("y-size", string(buf));
2497 snprintf(buf, sizeof(buf), "%d", x);
2498 geometry->add_property("x-pos", string(buf));
2499 snprintf(buf, sizeof(buf), "%d", y);
2500 geometry->add_property("y-pos", string(buf));
2501 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2502 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2503 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2504 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2505 geometry->add_property("edit-vertical-pane-pos", string(buf));
2507 node->add_child_nocopy (*geometry);
2510 maybe_add_mixer_strip_width (*node);
2512 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2513 snprintf (buf, sizeof(buf), "%f", frames_per_pixel);
2514 node->add_property ("zoom", buf);
2515 node->add_property ("snap-to", enum_2_string (_snap_type));
2516 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2517 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2518 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2519 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2520 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2521 node->add_property ("edit-point", enum_2_string (_edit_point));
2523 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2524 node->add_property ("playhead", buf);
2525 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2526 node->add_property ("left-frame", buf);
2527 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2528 node->add_property ("y-origin", buf);
2530 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2531 node->add_property ("maximised", _maximised ? "yes" : "no");
2532 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2533 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2534 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2535 node->add_property ("mouse-mode", enum2str(mouse_mode));
2536 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2537 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2539 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2541 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2542 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2545 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2547 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2548 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2551 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2552 node->add_property (X_("editor-list-page"), buf);
2554 if (button_bindings) {
2555 XMLNode* bb = new XMLNode (X_("Buttons"));
2556 button_bindings->save (*bb);
2557 node->add_child_nocopy (*bb);
2560 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2562 node->add_child_nocopy (selection->get_state ());
2563 node->add_child_nocopy (_regions->get_state ());
2565 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2566 node->add_property ("nudge-clock-value", buf);
2573 /** @param y y offset from the top of all trackviews.
2574 * @return pair: TimeAxisView that y is over, layer index.
2575 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2576 * in stacked or expanded region display mode, otherwise 0.
2578 std::pair<TimeAxisView *, double>
2579 Editor::trackview_by_y_position (double y)
2581 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2583 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2589 return std::make_pair ( (TimeAxisView *) 0, 0);
2592 /** Snap a position to the grid, if appropriate, taking into account current
2593 * grid settings and also the state of any snap modifier keys that may be pressed.
2594 * @param start Position to snap.
2595 * @param event Event to get current key modifier information from, or 0.
2598 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2600 if (!_session || !event) {
2604 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2605 if (_snap_mode == SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2609 if (_snap_mode != SnapOff) {
2610 snap_to_internal (start, direction, for_mark);
2616 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2618 if (!_session || _snap_mode == SnapOff) {
2622 snap_to_internal (start, direction, for_mark);
2626 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2628 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2629 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2631 switch (_snap_type) {
2632 case SnapToTimecodeFrame:
2633 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2634 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2636 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2640 case SnapToTimecodeSeconds:
2641 if (_session->config.get_timecode_offset_negative()) {
2642 start += _session->config.get_timecode_offset ();
2644 start -= _session->config.get_timecode_offset ();
2646 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2647 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2649 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2652 if (_session->config.get_timecode_offset_negative()) {
2653 start -= _session->config.get_timecode_offset ();
2655 start += _session->config.get_timecode_offset ();
2659 case SnapToTimecodeMinutes:
2660 if (_session->config.get_timecode_offset_negative()) {
2661 start += _session->config.get_timecode_offset ();
2663 start -= _session->config.get_timecode_offset ();
2665 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2666 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2668 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2670 if (_session->config.get_timecode_offset_negative()) {
2671 start -= _session->config.get_timecode_offset ();
2673 start += _session->config.get_timecode_offset ();
2677 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2683 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2685 const framepos_t one_second = _session->frame_rate();
2686 const framepos_t one_minute = _session->frame_rate() * 60;
2687 framepos_t presnap = start;
2691 switch (_snap_type) {
2692 case SnapToTimecodeFrame:
2693 case SnapToTimecodeSeconds:
2694 case SnapToTimecodeMinutes:
2695 return timecode_snap_to_internal (start, direction, for_mark);
2698 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2699 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2701 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2706 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2707 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2709 start = (framepos_t) floor ((double) start / one_second) * one_second;
2714 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2715 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2717 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2722 start = _session->tempo_map().round_to_bar (start, direction);
2726 start = _session->tempo_map().round_to_beat (start, direction);
2729 case SnapToBeatDiv128:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2732 case SnapToBeatDiv64:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2735 case SnapToBeatDiv32:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2738 case SnapToBeatDiv28:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2741 case SnapToBeatDiv24:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2744 case SnapToBeatDiv20:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2747 case SnapToBeatDiv16:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2750 case SnapToBeatDiv14:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2753 case SnapToBeatDiv12:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2756 case SnapToBeatDiv10:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2759 case SnapToBeatDiv8:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2762 case SnapToBeatDiv7:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2765 case SnapToBeatDiv6:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2768 case SnapToBeatDiv5:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2771 case SnapToBeatDiv4:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2774 case SnapToBeatDiv3:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2777 case SnapToBeatDiv2:
2778 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2786 _session->locations()->marks_either_side (start, before, after);
2788 if (before == max_framepos && after == max_framepos) {
2789 /* No marks to snap to, so just don't snap */
2791 } else if (before == max_framepos) {
2793 } else if (after == max_framepos) {
2795 } else if (before != max_framepos && after != max_framepos) {
2796 /* have before and after */
2797 if ((start - before) < (after - start)) {
2806 case SnapToRegionStart:
2807 case SnapToRegionEnd:
2808 case SnapToRegionSync:
2809 case SnapToRegionBoundary:
2810 if (!region_boundary_cache.empty()) {
2812 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2813 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2815 if (direction > 0) {
2816 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2818 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2821 if (next != region_boundary_cache.begin ()) {
2826 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2827 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2829 if (start > (p + n) / 2) {
2838 switch (_snap_mode) {
2844 if (presnap > start) {
2845 if (presnap > (start + unit_to_frame(snap_threshold))) {
2849 } else if (presnap < start) {
2850 if (presnap < (start - unit_to_frame(snap_threshold))) {
2856 /* handled at entry */
2864 Editor::setup_toolbar ()
2866 HBox* mode_box = manage(new HBox);
2867 mode_box->set_border_width (2);
2868 mode_box->set_spacing(4);
2870 HBox* mouse_mode_box = manage (new HBox);
2871 HBox* mouse_mode_hbox = manage (new HBox);
2872 VBox* mouse_mode_vbox = manage (new VBox);
2873 Alignment* mouse_mode_align = manage (new Alignment);
2875 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2876 // mouse_mode_size_group->add_widget (smart_mode_button);
2877 mouse_mode_size_group->add_widget (mouse_move_button);
2878 mouse_mode_size_group->add_widget (mouse_select_button);
2879 mouse_mode_size_group->add_widget (mouse_zoom_button);
2880 mouse_mode_size_group->add_widget (mouse_gain_button);
2881 mouse_mode_size_group->add_widget (mouse_timefx_button);
2882 mouse_mode_size_group->add_widget (mouse_audition_button);
2883 mouse_mode_size_group->add_widget (mouse_draw_button);
2884 mouse_mode_size_group->add_widget (internal_edit_button);
2886 /* make them just a bit bigger */
2887 mouse_move_button.set_size_request (-1, 30);
2889 mouse_mode_hbox->set_spacing (2);
2891 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2896 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2897 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2898 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2899 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2901 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2903 mouse_mode_align->add (*mouse_mode_vbox);
2904 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2906 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2908 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2909 if (!Profile->get_sae()) {
2910 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2912 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2914 edit_mode_selector.set_name ("EditModeSelector");
2915 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2916 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2918 mode_box->pack_start (edit_mode_selector, false, false);
2919 mode_box->pack_start (*mouse_mode_box, false, false);
2921 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2922 _mouse_mode_tearoff->set_name ("MouseModeBase");
2923 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2925 if (Profile->get_sae()) {
2926 _mouse_mode_tearoff->set_can_be_torn_off (false);
2929 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window()));
2931 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2932 &_mouse_mode_tearoff->tearoff_window(), 1));
2933 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2934 &_mouse_mode_tearoff->tearoff_window()));
2935 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2936 &_mouse_mode_tearoff->tearoff_window(), 1));
2940 _zoom_box.set_spacing (2);
2941 _zoom_box.set_border_width (2);
2945 zoom_in_button.set_name ("zoom button");
2946 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2947 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2948 zoom_in_button.set_image(::get_icon ("zoom_in"));
2949 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2950 zoom_in_button.set_related_action (act);
2952 zoom_out_button.set_name ("zoom button");
2953 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2954 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2955 zoom_out_button.set_image(::get_icon ("zoom_out"));
2956 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2957 zoom_out_button.set_related_action (act);
2959 zoom_out_full_button.set_name ("zoom button");
2960 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2961 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2963 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2964 zoom_out_full_button.set_related_action (act);
2966 zoom_focus_selector.set_name ("ZoomFocusSelector");
2967 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2968 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2970 _zoom_box.pack_start (zoom_out_button, false, false);
2971 _zoom_box.pack_start (zoom_in_button, false, false);
2972 _zoom_box.pack_start (zoom_out_full_button, false, false);
2974 _zoom_box.pack_start (zoom_focus_selector, false, false);
2976 /* Track zoom buttons */
2977 tav_expand_button.set_name ("zoom button");
2978 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2979 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2980 tav_expand_button.set_size_request (-1, 20);
2981 tav_expand_button.set_image(::get_icon ("tav_exp"));
2982 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2983 tav_expand_button.set_related_action (act);
2985 tav_shrink_button.set_name ("zoom button");
2986 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2987 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2988 tav_shrink_button.set_size_request (-1, 20);
2989 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2990 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2991 tav_shrink_button.set_related_action (act);
2993 _zoom_box.pack_start (tav_shrink_button);
2994 _zoom_box.pack_start (tav_expand_button);
2996 _zoom_tearoff = manage (new TearOff (_zoom_box));
2998 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2999 &_zoom_tearoff->tearoff_window()));
3000 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3001 &_zoom_tearoff->tearoff_window(), 0));
3002 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3003 &_zoom_tearoff->tearoff_window()));
3004 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3005 &_zoom_tearoff->tearoff_window(), 0));
3007 snap_box.set_spacing (2);
3008 snap_box.set_border_width (2);
3010 snap_type_selector.set_name ("SnapTypeSelector");
3011 set_popdown_strings (snap_type_selector, snap_type_strings);
3012 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3014 snap_mode_selector.set_name ("SnapModeSelector");
3015 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3016 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3018 edit_point_selector.set_name ("EditPointSelector");
3019 set_popdown_strings (edit_point_selector, edit_point_strings);
3020 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3022 snap_box.pack_start (snap_mode_selector, false, false);
3023 snap_box.pack_start (snap_type_selector, false, false);
3024 snap_box.pack_start (edit_point_selector, false, false);
3028 HBox *nudge_box = manage (new HBox);
3029 nudge_box->set_spacing (2);
3030 nudge_box->set_border_width (2);
3032 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3033 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3035 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3036 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3038 nudge_box->pack_start (nudge_backward_button, false, false);
3039 nudge_box->pack_start (nudge_forward_button, false, false);
3040 nudge_box->pack_start (*nudge_clock, false, false);
3043 /* Pack everything in... */
3045 HBox* hbox = manage (new HBox);
3046 hbox->set_spacing(10);
3048 _tools_tearoff = manage (new TearOff (*hbox));
3049 _tools_tearoff->set_name ("MouseModeBase");
3050 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3052 if (Profile->get_sae()) {
3053 _tools_tearoff->set_can_be_torn_off (false);
3056 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window()));
3058 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window(), 0));
3060 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window()));
3062 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window(), 0));
3065 toolbar_hbox.set_spacing (10);
3066 toolbar_hbox.set_border_width (1);
3068 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3069 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3070 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3072 hbox->pack_start (snap_box, false, false);
3073 if (!Profile->get_small_screen()) {
3074 hbox->pack_start (*nudge_box, false, false);
3076 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3078 hbox->pack_start (panic_box, false, false);
3082 toolbar_base.set_name ("ToolBarBase");
3083 toolbar_base.add (toolbar_hbox);
3085 _toolbar_viewport.add (toolbar_base);
3086 /* stick to the required height but allow width to vary if there's not enough room */
3087 _toolbar_viewport.set_size_request (1, -1);
3089 toolbar_frame.set_shadow_type (SHADOW_OUT);
3090 toolbar_frame.set_name ("BaseFrame");
3091 toolbar_frame.add (_toolbar_viewport);
3095 Editor::setup_tooltips ()
3097 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3098 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3099 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3100 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3101 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3102 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3103 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3104 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3105 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3106 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3107 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3108 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3109 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3110 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3111 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3112 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3113 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3114 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3115 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3116 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3117 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3118 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3119 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3123 Editor::convert_drop_to_paths (
3124 vector<string>& paths,
3125 const RefPtr<Gdk::DragContext>& /*context*/,
3128 const SelectionData& data,
3132 if (_session == 0) {
3136 vector<string> uris = data.get_uris();
3140 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3141 are actually URI lists. So do it by hand.
3144 if (data.get_target() != "text/plain") {
3148 /* Parse the "uri-list" format that Nautilus provides,
3149 where each pathname is delimited by \r\n.
3151 THERE MAY BE NO NULL TERMINATING CHAR!!!
3154 string txt = data.get_text();
3158 p = (const char *) malloc (txt.length() + 1);
3159 txt.copy (const_cast<char *> (p), txt.length(), 0);
3160 const_cast<char*>(p)[txt.length()] = '\0';
3166 while (g_ascii_isspace (*p))
3170 while (*q && (*q != '\n') && (*q != '\r')) {
3177 while (q > p && g_ascii_isspace (*q))
3182 uris.push_back (string (p, q - p + 1));
3186 p = strchr (p, '\n');
3198 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3200 if ((*i).substr (0,7) == "file://") {
3202 string const p = PBD::url_decode (*i);
3204 // scan forward past three slashes
3206 string::size_type slashcnt = 0;
3207 string::size_type n = 0;
3208 string::const_iterator x = p.begin();
3210 while (slashcnt < 3 && x != p.end()) {
3213 } else if (slashcnt == 3) {
3220 if (slashcnt != 3 || x == p.end()) {
3221 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3225 paths.push_back (p.substr (n - 1));
3233 Editor::new_tempo_section ()
3239 Editor::map_transport_state ()
3241 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3243 if (_session && _session->transport_stopped()) {
3244 have_pending_keyboard_selection = false;
3247 update_loop_range_view (true);
3253 Editor::begin_reversible_command (string name)
3256 _session->begin_reversible_command (name);
3261 Editor::begin_reversible_command (GQuark q)
3264 _session->begin_reversible_command (q);
3269 Editor::commit_reversible_command ()
3272 _session->commit_reversible_command ();
3277 Editor::history_changed ()
3281 if (undo_action && _session) {
3282 if (_session->undo_depth() == 0) {
3283 label = S_("Command|Undo");
3285 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3287 undo_action->property_label() = label;
3290 if (redo_action && _session) {
3291 if (_session->redo_depth() == 0) {
3294 label = string_compose(_("Redo (%1)"), _session->next_redo());
3296 redo_action->property_label() = label;
3301 Editor::duplicate_range (bool with_dialog)
3305 RegionSelection rs = get_regions_from_selection_and_entered ();
3307 if ( selection->time.length() == 0 && rs.empty()) {
3313 ArdourDialog win (_("Duplicate"));
3314 Label label (_("Number of duplications:"));
3315 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3316 SpinButton spinner (adjustment, 0.0, 1);
3319 win.get_vbox()->set_spacing (12);
3320 win.get_vbox()->pack_start (hbox);
3321 hbox.set_border_width (6);
3322 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3324 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3325 place, visually. so do this by hand.
3328 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3329 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3330 spinner.grab_focus();
3336 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3337 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3338 win.set_default_response (RESPONSE_ACCEPT);
3340 win.set_position (WIN_POS_MOUSE);
3342 spinner.grab_focus ();
3344 switch (win.run ()) {
3345 case RESPONSE_ACCEPT:
3351 times = adjustment.get_value();
3354 if ((current_mouse_mode() == Editing::MouseRange)) {
3355 if (selection->time.length()) {
3356 duplicate_selection (times);
3358 } else if (get_smart_mode()) {
3359 if (selection->time.length()) {
3360 duplicate_selection (times);
3362 duplicate_some_regions (rs, times);
3364 duplicate_some_regions (rs, times);
3369 Editor::set_edit_mode (EditMode m)
3371 Config->set_edit_mode (m);
3375 Editor::cycle_edit_mode ()
3377 switch (Config->get_edit_mode()) {
3379 if (Profile->get_sae()) {
3380 Config->set_edit_mode (Lock);
3382 Config->set_edit_mode (Splice);
3386 Config->set_edit_mode (Lock);
3389 Config->set_edit_mode (Slide);
3395 Editor::edit_mode_selection_done ()
3397 string s = edit_mode_selector.get_active_text ();
3400 Config->set_edit_mode (string_to_edit_mode (s));
3405 Editor::snap_type_selection_done ()
3407 string choice = snap_type_selector.get_active_text();
3408 SnapType snaptype = SnapToBeat;
3410 if (choice == _("Beats/2")) {
3411 snaptype = SnapToBeatDiv2;
3412 } else if (choice == _("Beats/3")) {
3413 snaptype = SnapToBeatDiv3;
3414 } else if (choice == _("Beats/4")) {
3415 snaptype = SnapToBeatDiv4;
3416 } else if (choice == _("Beats/5")) {
3417 snaptype = SnapToBeatDiv5;
3418 } else if (choice == _("Beats/6")) {
3419 snaptype = SnapToBeatDiv6;
3420 } else if (choice == _("Beats/7")) {
3421 snaptype = SnapToBeatDiv7;
3422 } else if (choice == _("Beats/8")) {
3423 snaptype = SnapToBeatDiv8;
3424 } else if (choice == _("Beats/10")) {
3425 snaptype = SnapToBeatDiv10;
3426 } else if (choice == _("Beats/12")) {
3427 snaptype = SnapToBeatDiv12;
3428 } else if (choice == _("Beats/14")) {
3429 snaptype = SnapToBeatDiv14;
3430 } else if (choice == _("Beats/16")) {
3431 snaptype = SnapToBeatDiv16;
3432 } else if (choice == _("Beats/20")) {
3433 snaptype = SnapToBeatDiv20;
3434 } else if (choice == _("Beats/24")) {
3435 snaptype = SnapToBeatDiv24;
3436 } else if (choice == _("Beats/28")) {
3437 snaptype = SnapToBeatDiv28;
3438 } else if (choice == _("Beats/32")) {
3439 snaptype = SnapToBeatDiv32;
3440 } else if (choice == _("Beats/64")) {
3441 snaptype = SnapToBeatDiv64;
3442 } else if (choice == _("Beats/128")) {
3443 snaptype = SnapToBeatDiv128;
3444 } else if (choice == _("Beats")) {
3445 snaptype = SnapToBeat;
3446 } else if (choice == _("Bars")) {
3447 snaptype = SnapToBar;
3448 } else if (choice == _("Marks")) {
3449 snaptype = SnapToMark;
3450 } else if (choice == _("Region starts")) {
3451 snaptype = SnapToRegionStart;
3452 } else if (choice == _("Region ends")) {
3453 snaptype = SnapToRegionEnd;
3454 } else if (choice == _("Region bounds")) {
3455 snaptype = SnapToRegionBoundary;
3456 } else if (choice == _("Region syncs")) {
3457 snaptype = SnapToRegionSync;
3458 } else if (choice == _("CD Frames")) {
3459 snaptype = SnapToCDFrame;
3460 } else if (choice == _("Timecode Frames")) {
3461 snaptype = SnapToTimecodeFrame;
3462 } else if (choice == _("Timecode Seconds")) {
3463 snaptype = SnapToTimecodeSeconds;
3464 } else if (choice == _("Timecode Minutes")) {
3465 snaptype = SnapToTimecodeMinutes;
3466 } else if (choice == _("Seconds")) {
3467 snaptype = SnapToSeconds;
3468 } else if (choice == _("Minutes")) {
3469 snaptype = SnapToMinutes;
3472 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3474 ract->set_active ();
3479 Editor::snap_mode_selection_done ()
3481 string choice = snap_mode_selector.get_active_text();
3482 SnapMode mode = SnapNormal;
3484 if (choice == _("No Grid")) {
3486 } else if (choice == _("Grid")) {
3488 } else if (choice == _("Magnetic")) {
3489 mode = SnapMagnetic;
3492 RefPtr<RadioAction> ract = snap_mode_action (mode);
3495 ract->set_active (true);
3500 Editor::cycle_edit_point (bool with_marker)
3502 switch (_edit_point) {
3504 set_edit_point_preference (EditAtPlayhead);
3506 case EditAtPlayhead:
3508 set_edit_point_preference (EditAtSelectedMarker);
3510 set_edit_point_preference (EditAtMouse);
3513 case EditAtSelectedMarker:
3514 set_edit_point_preference (EditAtMouse);
3520 Editor::edit_point_selection_done ()
3522 string choice = edit_point_selector.get_active_text();
3523 EditPoint ep = EditAtSelectedMarker;
3525 if (choice == _("Marker")) {
3526 set_edit_point_preference (EditAtSelectedMarker);
3527 } else if (choice == _("Playhead")) {
3528 set_edit_point_preference (EditAtPlayhead);
3530 set_edit_point_preference (EditAtMouse);
3533 RefPtr<RadioAction> ract = edit_point_action (ep);
3536 ract->set_active (true);
3541 Editor::zoom_focus_selection_done ()
3543 string choice = zoom_focus_selector.get_active_text();
3544 ZoomFocus focus_type = ZoomFocusLeft;
3546 if (choice == _("Left")) {
3547 focus_type = ZoomFocusLeft;
3548 } else if (choice == _("Right")) {
3549 focus_type = ZoomFocusRight;
3550 } else if (choice == _("Center")) {
3551 focus_type = ZoomFocusCenter;
3552 } else if (choice == _("Playhead")) {
3553 focus_type = ZoomFocusPlayhead;
3554 } else if (choice == _("Mouse")) {
3555 focus_type = ZoomFocusMouse;
3556 } else if (choice == _("Edit point")) {
3557 focus_type = ZoomFocusEdit;
3560 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3563 ract->set_active ();
3568 Editor::edit_controls_button_release (GdkEventButton* ev)
3570 if (Keyboard::is_context_menu_event (ev)) {
3571 ARDOUR_UI::instance()->add_route (this);
3572 } else if (ev->button == 1) {
3573 selection->clear_tracks ();
3580 Editor::mouse_select_button_release (GdkEventButton* ev)
3582 /* this handles just right-clicks */
3584 if (ev->button != 3) {
3592 Editor::set_zoom_focus (ZoomFocus f)
3594 string str = zoom_focus_strings[(int)f];
3596 if (str != zoom_focus_selector.get_active_text()) {
3597 zoom_focus_selector.set_active_text (str);
3600 if (zoom_focus != f) {
3607 Editor::cycle_zoom_focus ()
3609 switch (zoom_focus) {
3611 set_zoom_focus (ZoomFocusRight);
3613 case ZoomFocusRight:
3614 set_zoom_focus (ZoomFocusCenter);
3616 case ZoomFocusCenter:
3617 set_zoom_focus (ZoomFocusPlayhead);
3619 case ZoomFocusPlayhead:
3620 set_zoom_focus (ZoomFocusMouse);
3622 case ZoomFocusMouse:
3623 set_zoom_focus (ZoomFocusEdit);
3626 set_zoom_focus (ZoomFocusLeft);
3632 Editor::ensure_float (Window& win)
3634 win.set_transient_for (*this);
3638 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3640 /* recover or initialize pane positions. do this here rather than earlier because
3641 we don't want the positions to change the child allocations, which they seem to do.
3647 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3656 XMLNode* geometry = find_named_node (*node, "geometry");
3658 if (which == static_cast<Paned*> (&edit_pane)) {
3660 if (done & Horizontal) {
3664 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3665 _notebook_shrunk = string_is_affirmative (prop->value ());
3668 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3669 /* initial allocation is 90% to canvas, 10% to notebook */
3670 pos = (int) floor (alloc.get_width() * 0.90f);
3671 snprintf (buf, sizeof(buf), "%d", pos);
3673 pos = atoi (prop->value());
3676 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3677 edit_pane.set_position (pos);
3680 done = (Pane) (done | Horizontal);
3682 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3684 if (done & Vertical) {
3688 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3689 /* initial allocation is 90% to canvas, 10% to summary */
3690 pos = (int) floor (alloc.get_height() * 0.90f);
3691 snprintf (buf, sizeof(buf), "%d", pos);
3694 pos = atoi (prop->value());
3697 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3698 editor_summary_pane.set_position (pos);
3701 done = (Pane) (done | Vertical);
3706 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3708 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3709 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3710 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3711 top_hbox.remove (toolbar_frame);
3716 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3718 if (toolbar_frame.get_parent() == 0) {
3719 top_hbox.pack_end (toolbar_frame);
3724 Editor::set_show_measures (bool yn)
3726 if (_show_measures != yn) {
3729 if ((_show_measures = yn) == true) {
3731 tempo_lines->show();
3733 (void) redraw_measures ();
3740 Editor::toggle_follow_playhead ()
3742 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3744 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3745 set_follow_playhead (tact->get_active());
3749 /** @param yn true to follow playhead, otherwise false.
3750 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3753 Editor::set_follow_playhead (bool yn, bool catch_up)
3755 if (_follow_playhead != yn) {
3756 if ((_follow_playhead = yn) == true && catch_up) {
3758 reset_x_origin_to_follow_playhead ();
3765 Editor::toggle_stationary_playhead ()
3767 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3769 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3770 set_stationary_playhead (tact->get_active());
3775 Editor::set_stationary_playhead (bool yn)
3777 if (_stationary_playhead != yn) {
3778 if ((_stationary_playhead = yn) == true) {
3780 // FIXME need a 3.0 equivalent of this 2.X call
3781 // update_current_screen ();
3788 Editor::playlist_selector () const
3790 return *_playlist_selector;
3794 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3798 switch (_snap_type) {
3803 case SnapToBeatDiv128:
3806 case SnapToBeatDiv64:
3809 case SnapToBeatDiv32:
3812 case SnapToBeatDiv28:
3815 case SnapToBeatDiv24:
3818 case SnapToBeatDiv20:
3821 case SnapToBeatDiv16:
3824 case SnapToBeatDiv14:
3827 case SnapToBeatDiv12:
3830 case SnapToBeatDiv10:
3833 case SnapToBeatDiv8:
3836 case SnapToBeatDiv7:
3839 case SnapToBeatDiv6:
3842 case SnapToBeatDiv5:
3845 case SnapToBeatDiv4:
3848 case SnapToBeatDiv3:
3851 case SnapToBeatDiv2:
3857 return _session->tempo_map().meter_at (position).divisions_per_bar();
3862 case SnapToTimecodeFrame:
3863 case SnapToTimecodeSeconds:
3864 case SnapToTimecodeMinutes:
3867 case SnapToRegionStart:
3868 case SnapToRegionEnd:
3869 case SnapToRegionSync:
3870 case SnapToRegionBoundary:
3880 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3884 ret = nudge_clock->current_duration (pos);
3885 next = ret + 1; /* XXXX fix me */
3891 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3893 ArdourDialog dialog (_("Playlist Deletion"));
3894 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3895 "If it is kept, its audio files will not be cleaned.\n"
3896 "If it is deleted, audio files used by it alone will be cleaned."),
3899 dialog.set_position (WIN_POS_CENTER);
3900 dialog.get_vbox()->pack_start (label);
3904 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3905 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3906 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3908 switch (dialog.run ()) {
3909 case RESPONSE_ACCEPT:
3910 /* delete the playlist */
3914 case RESPONSE_REJECT:
3915 /* keep the playlist */
3927 Editor::audio_region_selection_covers (framepos_t where)
3929 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3930 if ((*a)->region()->covers (where)) {
3939 Editor::prepare_for_cleanup ()
3941 cut_buffer->clear_regions ();
3942 cut_buffer->clear_playlists ();
3944 selection->clear_regions ();
3945 selection->clear_playlists ();
3947 _regions->suspend_redisplay ();
3951 Editor::finish_cleanup ()
3953 _regions->resume_redisplay ();
3957 Editor::transport_loop_location()
3960 return _session->locations()->auto_loop_location();
3967 Editor::transport_punch_location()
3970 return _session->locations()->auto_punch_location();
3977 Editor::control_layout_scroll (GdkEventScroll* ev)
3979 if (Keyboard::some_magic_widget_has_focus()) {
3983 switch (ev->direction) {
3985 scroll_tracks_up_line ();
3989 case GDK_SCROLL_DOWN:
3990 scroll_tracks_down_line ();
3994 /* no left/right handling yet */
4002 Editor::session_state_saved (string)
4005 _snapshots->redisplay ();
4009 Editor::update_tearoff_visibility()
4011 bool visible = Config->get_keep_tearoffs();
4012 _mouse_mode_tearoff->set_visible (visible);
4013 _tools_tearoff->set_visible (visible);
4014 _zoom_tearoff->set_visible (visible);
4018 Editor::maximise_editing_space ()
4030 Editor::restore_editing_space ()
4042 * Make new playlists for a given track and also any others that belong
4043 * to the same active route group with the `edit' property.
4048 Editor::new_playlists (TimeAxisView* v)
4050 begin_reversible_command (_("new playlists"));
4051 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4052 _session->playlists->get (playlists);
4053 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4054 commit_reversible_command ();
4058 * Use a copy of the current playlist for a given track and also any others that belong
4059 * to the same active route group with the `edit' property.
4064 Editor::copy_playlists (TimeAxisView* v)
4066 begin_reversible_command (_("copy playlists"));
4067 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4068 _session->playlists->get (playlists);
4069 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4070 commit_reversible_command ();
4073 /** Clear the current playlist for a given track and also any others that belong
4074 * to the same active route group with the `edit' property.
4079 Editor::clear_playlists (TimeAxisView* v)
4081 begin_reversible_command (_("clear playlists"));
4082 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4083 _session->playlists->get (playlists);
4084 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4085 commit_reversible_command ();
4089 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4091 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4095 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4097 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4101 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4103 atv.clear_playlist ();
4107 Editor::on_key_press_event (GdkEventKey* ev)
4109 return key_press_focus_accelerator_handler (*this, ev);
4113 Editor::on_key_release_event (GdkEventKey* ev)
4115 return Gtk::Window::on_key_release_event (ev);
4116 // return key_press_focus_accelerator_handler (*this, ev);
4119 /** Queue up a change to the viewport x origin.
4120 * @param frame New x origin.
4123 Editor::reset_x_origin (framepos_t frame)
4125 pending_visual_change.add (VisualChange::TimeOrigin);
4126 pending_visual_change.time_origin = frame;
4127 ensure_visual_change_idle_handler ();
4131 Editor::reset_y_origin (double y)
4133 pending_visual_change.add (VisualChange::YOrigin);
4134 pending_visual_change.y_origin = y;
4135 ensure_visual_change_idle_handler ();
4139 Editor::reset_zoom (double fpp)
4141 clamp_frames_per_pixel (fpp);
4143 if (fpp == frames_per_pixel) {
4147 pending_visual_change.add (VisualChange::ZoomLevel);
4148 pending_visual_change.frames_per_pixel = fpp;
4149 ensure_visual_change_idle_handler ();
4153 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4155 reset_x_origin (frame);
4158 if (!no_save_visual) {
4159 undo_visual_stack.push_back (current_visual_state(false));
4163 Editor::VisualState::VisualState (bool with_tracks)
4164 : gui_state (with_tracks ? new GUIObjectState : 0)
4168 Editor::VisualState::~VisualState ()
4173 Editor::VisualState*
4174 Editor::current_visual_state (bool with_tracks)
4176 VisualState* vs = new VisualState (with_tracks);
4177 vs->y_position = vertical_adjustment.get_value();
4178 vs->frames_per_pixel = frames_per_pixel;
4179 vs->leftmost_frame = leftmost_frame;
4180 vs->zoom_focus = zoom_focus;
4183 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4190 Editor::undo_visual_state ()
4192 if (undo_visual_stack.empty()) {
4196 VisualState* vs = undo_visual_stack.back();
4197 undo_visual_stack.pop_back();
4200 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4202 use_visual_state (*vs);
4206 Editor::redo_visual_state ()
4208 if (redo_visual_stack.empty()) {
4212 VisualState* vs = redo_visual_stack.back();
4213 redo_visual_stack.pop_back();
4215 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4217 use_visual_state (*vs);
4221 Editor::swap_visual_state ()
4223 if (undo_visual_stack.empty()) {
4224 redo_visual_state ();
4226 undo_visual_state ();
4231 Editor::use_visual_state (VisualState& vs)
4233 PBD::Unwinder<bool> nsv (no_save_visual, true);
4235 _routes->suspend_redisplay ();
4237 vertical_adjustment.set_value (vs.y_position);
4239 set_zoom_focus (vs.zoom_focus);
4240 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_pixel);
4243 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4245 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4246 (*i)->reset_visual_state ();
4250 _routes->update_visibility ();
4251 _routes->resume_redisplay ();
4254 /** This is the core function that controls the zoom level of the canvas. It is called
4255 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4256 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4259 Editor::set_frames_per_pixel (double fpp)
4262 tempo_lines->tempo_map_changed();
4265 frames_per_pixel = fpp;
4267 /* convert fpu to frame count */
4269 framepos_t frames = (framepos_t) floor (frames_per_pixel * _visible_canvas_width);
4271 if (frames_per_pixel != zoom_range_clock->current_duration()) {
4272 zoom_range_clock->set (frames);
4275 bool const showing_time_selection = selection->time.length() > 0;
4277 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4278 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4279 (*i)->reshow_selection (selection->time);
4283 ZoomChanged (); /* EMIT_SIGNAL */
4285 //reset_scrolling_region ();
4287 if (playhead_cursor) {
4288 playhead_cursor->set_position (playhead_cursor->current_frame ());
4291 refresh_location_display();
4292 _summary->set_overlays_dirty ();
4294 update_marker_labels ();
4299 #ifdef WITH_VIDEOTIMELINE
4301 Editor::queue_visual_videotimeline_update ()
4304 * pending_visual_change.add (VisualChange::VideoTimeline);
4305 * or maybe even more specific: which videotimeline-image
4306 * currently it calls update_video_timeline() to update
4307 * _all outdated_ images on the video-timeline.
4308 * see 'exposeimg()' in video_image_frame.cc
4310 ensure_visual_change_idle_handler ();
4315 Editor::ensure_visual_change_idle_handler ()
4317 if (pending_visual_change.idle_handler_id < 0) {
4318 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4319 pending_visual_change.being_handled = false;
4324 Editor::_idle_visual_changer (void* arg)
4326 return static_cast<Editor*>(arg)->idle_visual_changer ();
4330 Editor::idle_visual_changer ()
4332 /* set_horizontal_position() below (and maybe other calls) call
4333 gtk_main_iteration(), so it's possible that a signal will be handled
4334 half-way through this method. If this signal wants an
4335 idle_visual_changer we must schedule another one after this one, so
4336 mark the idle_handler_id as -1 here to allow that. Also make a note
4337 that we are doing the visual change, so that changes in response to
4338 super-rapid-screen-update can be dropped if we are still processing
4342 pending_visual_change.idle_handler_id = -1;
4343 pending_visual_change.being_handled = true;
4345 VisualChange::Type p = pending_visual_change.pending;
4346 pending_visual_change.pending = (VisualChange::Type) 0;
4348 double const last_time_origin = horizontal_position ();
4350 if (p & VisualChange::ZoomLevel) {
4351 set_frames_per_pixel (pending_visual_change.frames_per_pixel);
4353 compute_fixed_ruler_scale ();
4355 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4356 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4358 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4359 current_bbt_points_begin, current_bbt_points_end);
4360 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4361 current_bbt_points_begin, current_bbt_points_end);
4362 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4365 #ifdef WITH_VIDEOTIMELINE
4366 if (p & VisualChange::ZoomLevel) {
4367 update_video_timeline();
4371 if (p & VisualChange::TimeOrigin) {
4372 set_horizontal_position (pending_visual_change.time_origin / frames_per_pixel);
4375 if (p & VisualChange::YOrigin) {
4376 vertical_adjustment.set_value (pending_visual_change.y_origin);
4379 if (last_time_origin == horizontal_position ()) {
4380 /* changed signal not emitted */
4381 update_fixed_rulers ();
4382 redisplay_tempo (true);
4384 #ifdef WITH_VIDEOTIMELINE
4385 if (!(p & VisualChange::ZoomLevel)) {
4386 update_video_timeline();
4390 _summary->set_overlays_dirty ();
4392 pending_visual_change.being_handled = false;
4393 return 0; /* this is always a one-shot call */
4396 struct EditorOrderTimeAxisSorter {
4397 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4398 return a->order () < b->order ();
4403 Editor::sort_track_selection (TrackViewList& sel)
4405 EditorOrderTimeAxisSorter cmp;
4410 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4413 framepos_t where = 0;
4414 EditPoint ep = _edit_point;
4416 if (from_context_menu && (ep == EditAtMouse)) {
4417 return event_frame (&context_click_event, 0, 0);
4420 if (entered_marker) {
4421 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4422 return entered_marker->position();
4425 if (ignore_playhead && ep == EditAtPlayhead) {
4426 ep = EditAtSelectedMarker;
4430 case EditAtPlayhead:
4431 where = _session->audible_frame();
4432 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4435 case EditAtSelectedMarker:
4436 if (!selection->markers.empty()) {
4438 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4441 where = loc->start();
4445 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4453 if (!mouse_frame (where, ignored)) {
4454 /* XXX not right but what can we do ? */
4458 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4466 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4468 if (!_session) return;
4470 begin_reversible_command (cmd);
4474 if ((tll = transport_loop_location()) == 0) {
4475 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4476 XMLNode &before = _session->locations()->get_state();
4477 _session->locations()->add (loc, true);
4478 _session->set_auto_loop_location (loc);
4479 XMLNode &after = _session->locations()->get_state();
4480 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4482 XMLNode &before = tll->get_state();
4483 tll->set_hidden (false, this);
4484 tll->set (start, end);
4485 XMLNode &after = tll->get_state();
4486 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4489 commit_reversible_command ();
4493 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4495 if (!_session) return;
4497 begin_reversible_command (cmd);
4501 if ((tpl = transport_punch_location()) == 0) {
4502 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4503 XMLNode &before = _session->locations()->get_state();
4504 _session->locations()->add (loc, true);
4505 _session->set_auto_loop_location (loc);
4506 XMLNode &after = _session->locations()->get_state();
4507 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4510 XMLNode &before = tpl->get_state();
4511 tpl->set_hidden (false, this);
4512 tpl->set (start, end);
4513 XMLNode &after = tpl->get_state();
4514 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4517 commit_reversible_command ();
4520 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4521 * @param rs List to which found regions are added.
4522 * @param where Time to look at.
4523 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4526 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4528 const TrackViewList* tracks;
4531 tracks = &track_views;
4536 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4538 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4541 boost::shared_ptr<Track> tr;
4542 boost::shared_ptr<Playlist> pl;
4544 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4546 boost::shared_ptr<RegionList> regions = pl->regions_at (
4547 (framepos_t) floor ( (double) where * tr->speed()));
4549 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4550 RegionView* rv = rtv->view()->find_view (*i);
4561 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4563 const TrackViewList* tracks;
4566 tracks = &track_views;
4571 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4572 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4574 boost::shared_ptr<Track> tr;
4575 boost::shared_ptr<Playlist> pl;
4577 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4579 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4580 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4582 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4584 RegionView* rv = rtv->view()->find_view (*i);
4595 /** Start with regions that are selected. Then add equivalent regions
4596 * on tracks in the same active edit-enabled route group as any of
4597 * the regions that we started with.
4601 Editor::get_regions_from_selection ()
4603 return get_equivalent_regions (selection->regions, ARDOUR::Properties::select.property_id);
4606 /** Get regions using the following method:
4608 * Make an initial region list using the selected regions, unless
4609 * the edit point is `mouse' and the mouse is over an unselected
4610 * region. In this case, start with just that region.
4612 * Then, add equivalent regions in active edit groups to the region list.
4614 * Then, search the list of selected tracks to find any selected tracks which
4615 * do not contain regions already in the region list. If there are no selected
4616 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4617 * than just the selected.
4619 * Add any regions that are under the edit point on these tracks to get the
4620 * returned region list.
4622 * The rationale here is that the mouse edit point is special in that
4623 * its position describes both a time and a track; the other edit
4624 * modes only describe a time. Hence if the edit point is `mouse' we
4625 * ignore selected tracks, as we assume the user means something by
4626 * pointing at a particular track. Also in this case we take note of
4627 * the region directly under the edit point, as there is always just one
4628 * (rather than possibly several with non-mouse edit points).
4632 Editor::get_regions_from_selection_and_edit_point ()
4634 RegionSelection regions;
4636 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4637 regions.add (entered_regionview);
4639 regions = selection->regions;
4642 TrackViewList tracks;
4644 if (_edit_point != EditAtMouse) {
4645 tracks = selection->tracks;
4648 /* Add any other regions that are in the same
4649 edit-activated route group as one of our regions.
4651 regions = get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4652 framepos_t const where = get_preferred_edit_position ();
4654 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4655 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4656 * is enabled, so consider all tracks
4658 tracks = track_views;
4661 if (!tracks.empty()) {
4662 /* now search the selected tracks for tracks which don't
4663 already contain regions to be acted upon, and get regions at
4664 the edit point on those tracks too.
4666 TrackViewList tracks_without_relevant_regions;
4668 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4669 if (!regions.involves (**t)) {
4670 /* there are no equivalent regions on this track */
4671 tracks_without_relevant_regions.push_back (*t);
4675 if (!tracks_without_relevant_regions.empty()) {
4676 /* there are some selected tracks with neither selected
4677 * regions or their equivalents: act upon all regions in
4680 get_regions_at (regions, where, tracks_without_relevant_regions);
4687 /** Start with regions that are selected, or the entered regionview if none are selected.
4688 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4689 * of the regions that we started with.
4693 Editor::get_regions_from_selection_and_entered ()
4695 RegionSelection regions = selection->regions;
4697 if (regions.empty() && entered_regionview) {
4698 regions.add (entered_regionview);
4701 return get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4705 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4707 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4709 RouteTimeAxisView* tatv;
4711 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4713 boost::shared_ptr<Playlist> pl;
4714 vector<boost::shared_ptr<Region> > results;
4716 boost::shared_ptr<Track> tr;
4718 if ((tr = tatv->track()) == 0) {
4723 if ((pl = (tr->playlist())) != 0) {
4724 if (src_comparison) {
4725 pl->get_source_equivalent_regions (region, results);
4727 pl->get_region_list_equivalent_regions (region, results);
4731 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4732 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4733 regions.push_back (marv);
4742 Editor::show_rhythm_ferret ()
4744 if (rhythm_ferret == 0) {
4745 rhythm_ferret = new RhythmFerret(*this);
4748 rhythm_ferret->set_session (_session);
4749 rhythm_ferret->show ();
4750 rhythm_ferret->present ();
4754 Editor::first_idle ()
4756 MessageDialog* dialog = 0;
4758 if (track_views.size() > 1) {
4759 dialog = new MessageDialog (
4761 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4765 ARDOUR_UI::instance()->flush_pending ();
4768 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4772 // first idle adds route children (automation tracks), so we need to redisplay here
4773 _routes->redisplay ();
4780 Editor::_idle_resize (gpointer arg)
4782 return ((Editor*)arg)->idle_resize ();
4786 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4788 if (resize_idle_id < 0) {
4789 resize_idle_id = g_idle_add (_idle_resize, this);
4790 _pending_resize_amount = 0;
4793 /* make a note of the smallest resulting height, so that we can clamp the
4794 lower limit at TimeAxisView::hSmall */
4796 int32_t min_resulting = INT32_MAX;
4798 _pending_resize_amount += h;
4799 _pending_resize_view = view;
4801 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4803 if (selection->tracks.contains (_pending_resize_view)) {
4804 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4805 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4809 if (min_resulting < 0) {
4814 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4815 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4819 /** Handle pending resizing of tracks */
4821 Editor::idle_resize ()
4823 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4825 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4826 selection->tracks.contains (_pending_resize_view)) {
4828 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4829 if (*i != _pending_resize_view) {
4830 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4835 _pending_resize_amount = 0;
4837 _group_tabs->set_dirty ();
4838 resize_idle_id = -1;
4846 ENSURE_GUI_THREAD (*this, &Editor::located);
4849 playhead_cursor->set_position (_session->audible_frame ());
4850 if (_follow_playhead && !_pending_initial_locate) {
4851 reset_x_origin_to_follow_playhead ();
4855 _pending_locate_request = false;
4856 _pending_initial_locate = false;
4860 Editor::region_view_added (RegionView *)
4862 _summary->set_dirty ();
4866 Editor::region_view_removed ()
4868 _summary->set_dirty ();
4872 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4874 TrackViewList::const_iterator j = track_views.begin ();
4875 while (j != track_views.end()) {
4876 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4877 if (rtv && rtv->route() == r) {
4888 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4892 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4893 TimeAxisView* tv = axis_view_from_route (*i);
4903 Editor::add_routes (RouteList& routes)
4905 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4907 RouteTimeAxisView *rtv;
4908 list<RouteTimeAxisView*> new_views;
4910 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4911 boost::shared_ptr<Route> route = (*x);
4913 if (route->is_hidden() || route->is_monitor()) {
4917 DataType dt = route->input()->default_type();
4919 if (dt == ARDOUR::DataType::AUDIO) {
4920 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4921 rtv->set_route (route);
4922 } else if (dt == ARDOUR::DataType::MIDI) {
4923 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4924 rtv->set_route (route);
4926 throw unknown_type();
4929 new_views.push_back (rtv);
4930 track_views.push_back (rtv);
4932 rtv->effective_gain_display ();
4934 if (internal_editing()) {
4935 rtv->enter_internal_edit_mode ();
4937 rtv->leave_internal_edit_mode ();
4940 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4941 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4944 _routes->routes_added (new_views);
4945 _summary->routes_added (new_views);
4947 if (show_editor_mixer_when_tracks_arrive) {
4948 show_editor_mixer (true);
4951 editor_list_button.set_sensitive (true);
4955 Editor::timeaxisview_deleted (TimeAxisView *tv)
4957 if (_session && _session->deletion_in_progress()) {
4958 /* the situation is under control */
4962 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4964 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4966 _routes->route_removed (tv);
4968 if (tv == entered_track) {
4972 TimeAxisView::Children c = tv->get_child_list ();
4973 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4974 if (entered_track == i->get()) {
4979 /* remove it from the list of track views */
4981 TrackViewList::iterator i;
4983 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4984 i = track_views.erase (i);
4987 /* update whatever the current mixer strip is displaying, if revelant */
4989 boost::shared_ptr<Route> route;
4992 route = rtav->route ();
4995 if (current_mixer_strip && current_mixer_strip->route() == route) {
4997 TimeAxisView* next_tv;
4999 if (track_views.empty()) {
5001 } else if (i == track_views.end()) {
5002 next_tv = track_views.front();
5009 set_selected_mixer_strip (*next_tv);
5011 /* make the editor mixer strip go away setting the
5012 * button to inactive (which also unticks the menu option)
5015 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5021 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5023 if (apply_to_selection) {
5024 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5026 TrackSelection::iterator j = i;
5029 hide_track_in_display (*i, false);
5034 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5036 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5037 // this will hide the mixer strip
5038 set_selected_mixer_strip (*tv);
5041 _routes->hide_track_in_display (*tv);
5046 Editor::sync_track_view_list_and_routes ()
5048 track_views = TrackViewList (_routes->views ());
5050 _summary->set_dirty ();
5051 _group_tabs->set_dirty ();
5053 return false; // do not call again (until needed)
5057 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5059 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5064 /** Find a RouteTimeAxisView by the ID of its route */
5066 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5068 RouteTimeAxisView* v;
5070 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5071 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5072 if(v->route()->id() == id) {
5082 Editor::fit_route_group (RouteGroup *g)
5084 TrackViewList ts = axis_views_from_routes (g->route_list ());
5089 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5091 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5094 _session->cancel_audition ();
5098 if (_session->is_auditioning()) {
5099 _session->cancel_audition ();
5100 if (r == last_audition_region) {
5105 _session->audition_region (r);
5106 last_audition_region = r;
5111 Editor::hide_a_region (boost::shared_ptr<Region> r)
5113 r->set_hidden (true);
5117 Editor::show_a_region (boost::shared_ptr<Region> r)
5119 r->set_hidden (false);
5123 Editor::audition_region_from_region_list ()
5125 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5129 Editor::hide_region_from_region_list ()
5131 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5135 Editor::show_region_in_region_list ()
5137 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5141 Editor::step_edit_status_change (bool yn)
5144 start_step_editing ();
5146 stop_step_editing ();
5151 Editor::start_step_editing ()
5153 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5157 Editor::stop_step_editing ()
5159 step_edit_connection.disconnect ();
5163 Editor::check_step_edit ()
5165 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5166 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5168 mtv->check_step_edit ();
5172 return true; // do it again, till we stop
5176 Editor::scroll_press (Direction dir)
5178 ++_scroll_callbacks;
5180 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5181 /* delay the first auto-repeat */
5187 scroll_backward (1);
5195 scroll_tracks_up_line ();
5199 scroll_tracks_down_line ();
5203 /* do hacky auto-repeat */
5204 if (!_scroll_connection.connected ()) {
5206 _scroll_connection = Glib::signal_timeout().connect (
5207 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5210 _scroll_callbacks = 0;
5217 Editor::scroll_release ()
5219 _scroll_connection.disconnect ();
5222 /** Queue a change for the Editor viewport x origin to follow the playhead */
5224 Editor::reset_x_origin_to_follow_playhead ()
5226 framepos_t const frame = playhead_cursor->current_frame ();
5228 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5230 if (_session->transport_speed() < 0) {
5232 if (frame > (current_page_frames() / 2)) {
5233 center_screen (frame-(current_page_frames()/2));
5235 center_screen (current_page_frames()/2);
5242 if (frame < leftmost_frame) {
5244 if (_session->transport_rolling()) {
5245 /* rolling; end up with the playhead at the right of the page */
5246 l = frame - current_page_frames ();
5248 /* not rolling: end up with the playhead 1/4 of the way along the page */
5249 l = frame - current_page_frames() / 4;
5253 if (_session->transport_rolling()) {
5254 /* rolling: end up with the playhead on the left of the page */
5257 /* not rolling: end up with the playhead 3/4 of the way along the page */
5258 l = frame - 3 * current_page_frames() / 4;
5266 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5272 Editor::super_rapid_screen_update ()
5274 if (!_session || !_session->engine().running()) {
5278 /* METERING / MIXER STRIPS */
5280 /* update track meters, if required */
5281 if (is_mapped() && meters_running) {
5282 RouteTimeAxisView* rtv;
5283 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5284 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5285 rtv->fast_update ();
5290 /* and any current mixer strip */
5291 if (current_mixer_strip) {
5292 current_mixer_strip->fast_update ();
5295 /* PLAYHEAD AND VIEWPORT */
5297 framepos_t const frame = _session->audible_frame();
5299 /* There are a few reasons why we might not update the playhead / viewport stuff:
5301 * 1. we don't update things when there's a pending locate request, otherwise
5302 * when the editor requests a locate there is a chance that this method
5303 * will move the playhead before the locate request is processed, causing
5305 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5306 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5309 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5311 last_update_frame = frame;
5313 if (!_dragging_playhead) {
5314 playhead_cursor->set_position (frame);
5317 if (!_stationary_playhead) {
5319 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5320 /* We only do this if we aren't already
5321 handling a visual change (ie if
5322 pending_visual_change.being_handled is
5323 false) so that these requests don't stack
5324 up there are too many of them to handle in
5327 reset_x_origin_to_follow_playhead ();
5332 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5336 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5337 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_pixel;
5338 if (target <= 0.0) {
5341 if (fabs(target - current) < current_page_frames() / frames_per_pixel) {
5342 target = (target * 0.15) + (current * 0.85);
5348 set_horizontal_position (current);
5357 Editor::session_going_away ()
5359 _have_idled = false;
5361 _session_connections.drop_connections ();
5363 super_rapid_screen_update_connection.disconnect ();
5365 selection->clear ();
5366 cut_buffer->clear ();
5368 clicked_regionview = 0;
5369 clicked_axisview = 0;
5370 clicked_routeview = 0;
5371 entered_regionview = 0;
5373 last_update_frame = 0;
5376 playhead_cursor->hide ();
5378 /* rip everything out of the list displays */
5382 _route_groups->clear ();
5384 /* do this first so that deleting a track doesn't reset cms to null
5385 and thus cause a leak.
5388 if (current_mixer_strip) {
5389 if (current_mixer_strip->get_parent() != 0) {
5390 global_hpacker.remove (*current_mixer_strip);
5392 delete current_mixer_strip;
5393 current_mixer_strip = 0;
5396 /* delete all trackviews */
5398 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5401 track_views.clear ();
5403 zoom_range_clock->set_session (0);
5404 nudge_clock->set_session (0);
5406 editor_list_button.set_active(false);
5407 editor_list_button.set_sensitive(false);
5409 /* clear tempo/meter rulers */
5410 remove_metric_marks ();
5412 clear_marker_display ();
5414 stop_step_editing ();
5416 /* get rid of any existing editor mixer strip */
5418 WindowTitle title(Glib::get_application_name());
5419 title += _("Editor");
5421 set_title (title.get_string());
5423 SessionHandlePtr::session_going_away ();
5428 Editor::show_editor_list (bool yn)
5431 _the_notebook.show ();
5433 _the_notebook.hide ();
5438 Editor::change_region_layering_order (bool from_context_menu)
5440 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5442 if (!clicked_routeview) {
5443 if (layering_order_editor) {
5444 layering_order_editor->hide ();
5449 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5455 boost::shared_ptr<Playlist> pl = track->playlist();
5461 if (layering_order_editor == 0) {
5462 layering_order_editor = new RegionLayeringOrderEditor (*this);
5463 layering_order_editor->set_position (WIN_POS_MOUSE);
5466 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5467 layering_order_editor->maybe_present ();
5471 Editor::update_region_layering_order_editor ()
5473 if (layering_order_editor && layering_order_editor->is_visible ()) {
5474 change_region_layering_order (true);
5479 Editor::setup_fade_images ()
5481 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5482 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5483 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5484 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5485 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5487 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5488 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5489 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5490 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5491 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5493 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5494 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5495 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5496 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5497 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5499 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5500 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5501 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5502 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5503 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5507 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5509 Editor::action_menu_item (std::string const & name)
5511 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5514 return *manage (a->create_menu_item ());
5518 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5520 EventBox* b = manage (new EventBox);
5521 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5522 Label* l = manage (new Label (name));
5526 _the_notebook.append_page (widget, *b);
5530 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5532 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5533 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5536 if (ev->type == GDK_2BUTTON_PRESS) {
5538 /* double-click on a notebook tab shrinks or expands the notebook */
5540 if (_notebook_shrunk) {
5541 if (pre_notebook_shrink_pane_width) {
5542 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5544 _notebook_shrunk = false;
5546 pre_notebook_shrink_pane_width = edit_pane.get_position();
5548 /* this expands the LHS of the edit pane to cover the notebook
5549 PAGE but leaves the tabs visible.
5551 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5552 _notebook_shrunk = true;
5560 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5562 using namespace Menu_Helpers;
5564 MenuList& items = _control_point_context_menu.items ();
5567 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5568 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5569 if (!can_remove_control_point (item)) {
5570 items.back().set_sensitive (false);
5573 _control_point_context_menu.popup (event->button.button, event->button.time);
5577 Editor::shift_key_released ()
5579 _stepping_axis_view = 0;
5584 Editor::save_canvas_state ()
5586 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5587 string path = string_compose ("%1/canvas-state.xml", _session->path());