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"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "button_joiner.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.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 show_me_the_size (Requisition* r, const char* what)
214 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
218 pane_size_watcher (Paned* pane)
220 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
224 Quartz: impossible to access
226 so stop that by preventing it from ever getting too narrow. 35
227 pixels is basically a rough guess at the tab width.
232 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
234 gint pos = pane->get_position ();
236 if (pos > max_width_of_lhs) {
237 pane->set_position (max_width_of_lhs);
242 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
244 /* time display buttons */
245 , minsec_label (_("Mins:Secs"))
246 , bbt_label (_("Bars:Beats"))
247 , timecode_label (_("Timecode"))
248 , samples_label (_("Samples"))
249 , tempo_label (_("Tempo"))
250 , meter_label (_("Meter"))
251 , mark_label (_("Location Markers"))
252 , range_mark_label (_("Range Markers"))
253 , transport_mark_label (_("Loop/Punch Ranges"))
254 , cd_mark_label (_("CD Markers"))
255 , edit_packer (4, 4, true)
257 /* the values here don't matter: layout widgets
258 reset them as needed.
261 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
263 /* tool bar related */
265 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
269 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
274 , image_socket_listener(0)
279 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
280 , meters_running(false)
281 , _pending_locate_request (false)
282 , _pending_initial_locate (false)
283 , _last_cut_copy_source_track (0)
285 , _region_selection_change_updates_region_list (true)
286 , _following_mixer_selection (false)
287 , _control_point_toggled_on_press (false)
288 , _stepping_axis_view (0)
292 /* we are a singleton */
294 PublicEditor::_instance = this;
298 selection = new Selection (this);
299 cut_buffer = new Selection (this);
301 clicked_regionview = 0;
302 clicked_axisview = 0;
303 clicked_routeview = 0;
304 clicked_control_point = 0;
305 last_update_frame = 0;
306 pre_press_cursor = 0;
307 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 snap_threshold = 5.0;
321 bbt_beat_subdivision = 4;
324 last_autoscroll_x = 0;
325 last_autoscroll_y = 0;
326 autoscroll_active = false;
327 autoscroll_timeout_tag = -1;
332 current_interthread_info = 0;
333 _show_measures = true;
335 show_gain_after_trim = false;
337 have_pending_keyboard_selection = false;
338 _follow_playhead = true;
339 _stationary_playhead = false;
340 editor_ruler_menu = 0;
341 no_ruler_shown_update = false;
343 range_marker_menu = 0;
344 marker_menu_item = 0;
345 tempo_or_meter_marker_menu = 0;
346 transport_marker_menu = 0;
347 new_transport_marker_menu = 0;
348 editor_mixer_strip_width = Wide;
349 show_editor_mixer_when_tracks_arrive = false;
350 region_edit_menu_split_multichannel_item = 0;
351 region_edit_menu_split_item = 0;
354 current_stepping_trackview = 0;
356 entered_regionview = 0;
358 clear_entered_track = false;
361 button_release_can_deselect = true;
362 _dragging_playhead = false;
363 _dragging_edit_point = false;
364 select_new_marker = false;
366 layering_order_editor = 0;
367 no_save_visual = false;
369 within_track_canvas = false;
371 scrubbing_direction = 0;
375 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
376 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
377 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
378 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
379 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
381 _edit_point = EditAtMouse;
382 _internal_editing = false;
383 current_canvas_cursor = 0;
385 frames_per_unit = 2048; /* too early to use reset_zoom () */
387 _scroll_callbacks = 0;
389 zoom_focus = ZoomFocusLeft;
390 set_zoom_focus (ZoomFocusLeft);
391 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
393 bbt_label.set_name ("EditorTimeButton");
394 bbt_label.set_size_request (-1, (int)timebar_height);
395 bbt_label.set_alignment (1.0, 0.5);
396 bbt_label.set_padding (5,0);
398 bbt_label.set_no_show_all();
399 minsec_label.set_name ("EditorTimeButton");
400 minsec_label.set_size_request (-1, (int)timebar_height);
401 minsec_label.set_alignment (1.0, 0.5);
402 minsec_label.set_padding (5,0);
403 minsec_label.hide ();
404 minsec_label.set_no_show_all();
405 timecode_label.set_name ("EditorTimeButton");
406 timecode_label.set_size_request (-1, (int)timebar_height);
407 timecode_label.set_alignment (1.0, 0.5);
408 timecode_label.set_padding (5,0);
409 timecode_label.hide ();
410 timecode_label.set_no_show_all();
411 samples_label.set_name ("EditorTimeButton");
412 samples_label.set_size_request (-1, (int)timebar_height);
413 samples_label.set_alignment (1.0, 0.5);
414 samples_label.set_padding (5,0);
415 samples_label.hide ();
416 samples_label.set_no_show_all();
418 tempo_label.set_name ("EditorTimeButton");
419 tempo_label.set_size_request (-1, (int)timebar_height);
420 tempo_label.set_alignment (1.0, 0.5);
421 tempo_label.set_padding (5,0);
423 tempo_label.set_no_show_all();
425 meter_label.set_name ("EditorTimeButton");
426 meter_label.set_size_request (-1, (int)timebar_height);
427 meter_label.set_alignment (1.0, 0.5);
428 meter_label.set_padding (5,0);
430 meter_label.set_no_show_all();
432 mark_label.set_name ("EditorTimeButton");
433 mark_label.set_size_request (-1, (int)timebar_height);
434 mark_label.set_alignment (1.0, 0.5);
435 mark_label.set_padding (5,0);
437 mark_label.set_no_show_all();
439 cd_mark_label.set_name ("EditorTimeButton");
440 cd_mark_label.set_size_request (-1, (int)timebar_height);
441 cd_mark_label.set_alignment (1.0, 0.5);
442 cd_mark_label.set_padding (5,0);
443 cd_mark_label.hide();
444 cd_mark_label.set_no_show_all();
446 range_mark_label.set_name ("EditorTimeButton");
447 range_mark_label.set_size_request (-1, (int)timebar_height);
448 range_mark_label.set_alignment (1.0, 0.5);
449 range_mark_label.set_padding (5,0);
450 range_mark_label.hide();
451 range_mark_label.set_no_show_all();
453 transport_mark_label.set_name ("EditorTimeButton");
454 transport_mark_label.set_size_request (-1, (int)timebar_height);
455 transport_mark_label.set_alignment (1.0, 0.5);
456 transport_mark_label.set_padding (5,0);
457 transport_mark_label.hide();
458 transport_mark_label.set_no_show_all();
460 initialize_rulers ();
461 initialize_canvas ();
463 _summary = new EditorSummary (this);
465 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
466 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
468 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
470 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
471 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
473 edit_controls_vbox.set_spacing (0);
474 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
475 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
477 HBox* h = manage (new HBox);
478 _group_tabs = new EditorGroupTabs (this);
479 h->pack_start (*_group_tabs, PACK_SHRINK);
480 h->pack_start (edit_controls_vbox);
481 controls_layout.add (*h);
483 controls_layout.set_name ("EditControlsBase");
484 controls_layout.add_events (Gdk::SCROLL_MASK);
485 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
487 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
488 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
490 _cursors = new MouseCursors;
492 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
493 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
494 0.0, 1.0, 100.0, 1.0));
496 pad_line_1->property_color_rgba() = 0xFF0000FF;
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_button_event_box.add (time_button_vbox);
509 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 /* these enable us to have a dedicated window (for cursor setting, etc.)
513 for the canvas areas.
516 track_canvas_event_box.add (*track_canvas);
518 time_canvas_event_box.add (time_canvas_vbox);
519 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
521 edit_packer.set_col_spacings (0);
522 edit_packer.set_row_spacings (0);
523 edit_packer.set_homogeneous (false);
524 edit_packer.set_border_width (0);
525 edit_packer.set_name ("EditorWindow");
527 /* labels for the rulers */
528 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
529 /* labels for the marker "tracks" */
530 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
532 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
534 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
536 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
538 bottom_hbox.set_border_width (2);
539 bottom_hbox.set_spacing (3);
541 _route_groups = new EditorRouteGroups (this);
542 _routes = new EditorRoutes (this);
543 _regions = new EditorRegions (this);
544 _snapshots = new EditorSnapshots (this);
545 _locations = new EditorLocations (this);
547 add_notebook_page (_("Regions"), _regions->widget ());
548 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
549 add_notebook_page (_("Snapshots"), _snapshots->widget ());
550 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
551 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
553 _the_notebook.set_show_tabs (true);
554 _the_notebook.set_scrollable (true);
555 _the_notebook.popup_disable ();
556 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
557 _the_notebook.show_all ();
559 _notebook_shrunk = false;
561 editor_summary_pane.pack1(edit_packer);
563 Button* summary_arrows_left_left = manage (new Button);
564 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
565 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
566 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 Button* summary_arrows_left_right = manage (new Button);
569 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
570 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
571 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 VBox* summary_arrows_left = manage (new VBox);
574 summary_arrows_left->pack_start (*summary_arrows_left_left);
575 summary_arrows_left->pack_start (*summary_arrows_left_right);
577 Button* summary_arrows_right_up = manage (new Button);
578 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
579 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
580 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 Button* summary_arrows_right_down = manage (new Button);
583 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
584 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
585 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 VBox* summary_arrows_right = manage (new VBox);
588 summary_arrows_right->pack_start (*summary_arrows_right_up);
589 summary_arrows_right->pack_start (*summary_arrows_right_down);
591 Frame* summary_frame = manage (new Frame);
592 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
594 summary_frame->add (*_summary);
595 summary_frame->show ();
597 _summary_hbox.pack_start (*summary_arrows_left, false, false);
598 _summary_hbox.pack_start (*summary_frame, true, true);
599 _summary_hbox.pack_start (*summary_arrows_right, false, false);
601 editor_summary_pane.pack2 (_summary_hbox);
603 edit_pane.pack1 (editor_summary_pane, true, true);
604 edit_pane.pack2 (_the_notebook, false, true);
606 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
608 /* XXX: editor_summary_pane might need similar to the edit_pane */
610 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
612 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
615 top_hbox.pack_start (toolbar_frame);
617 HBox *hbox = manage (new HBox);
618 hbox->pack_start (edit_pane, true, true);
620 global_vpacker.pack_start (top_hbox, false, false);
621 global_vpacker.pack_start (*hbox, true, true);
623 global_hpacker.pack_start (global_vpacker, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager->get_accel_group());
628 status_bar_hpacker.show ();
630 vpacker.pack_end (status_bar_hpacker, false, false);
631 vpacker.pack_end (global_hpacker, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
636 /* when we start using our own keybinding system for the editor, this
637 * will be uncommented
643 _snap_type = SnapToBeat;
644 set_snap_to (_snap_type);
645 _snap_mode = SnapOff;
646 set_snap_mode (_snap_mode);
647 set_mouse_mode (MouseObject, true);
648 pre_internal_mouse_mode = MouseObject;
649 pre_internal_snap_type = _snap_type;
650 pre_internal_snap_mode = _snap_mode;
651 internal_snap_type = _snap_type;
652 internal_snap_mode = _snap_mode;
653 set_edit_point_preference (EditAtMouse, true);
655 _playlist_selector = new PlaylistSelector();
656 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
658 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
662 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
663 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
665 nudge_forward_button.set_name ("TransportButton");
666 nudge_backward_button.set_name ("TransportButton");
668 fade_context_menu.set_name ("ArdourContextMenu");
670 /* icons, titles, WM stuff */
672 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
673 Glib::RefPtr<Gdk::Pixbuf> icon;
675 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
676 window_icons.push_back (icon);
678 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
679 window_icons.push_back (icon);
681 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
682 window_icons.push_back (icon);
684 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
685 window_icons.push_back (icon);
687 if (!window_icons.empty()) {
688 // set_icon_list (window_icons);
689 set_default_icon_list (window_icons);
692 WindowTitle title(Glib::get_application_name());
693 title += _("Editor");
694 set_title (title.get_string());
695 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
698 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
700 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
701 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
703 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
705 /* allow external control surfaces/protocols to do various things */
707 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
708 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
709 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
710 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
711 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
712 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
713 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
714 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
715 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
716 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
717 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
718 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
719 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
720 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
722 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
723 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
724 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
725 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
726 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
728 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
730 /* problematic: has to return a value and thus cannot be x-thread */
732 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
734 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
736 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
738 _ignore_region_action = false;
739 _last_region_menu_was_main = false;
740 _popup_region_menu_item = 0;
742 _show_marker_lines = false;
743 _over_region_trim_target = false;
745 /* Button bindings */
747 button_bindings = new Bindings;
749 XMLNode* node = button_settings();
751 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
752 button_bindings->load (**i);
759 setup_fade_images ();
765 if(image_socket_listener) {
766 if(image_socket_listener->is_connected())
768 image_socket_listener->close_connection() ;
771 delete image_socket_listener ;
772 image_socket_listener = 0 ;
776 delete button_bindings;
778 delete _route_groups;
784 Editor::button_settings () const
786 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
787 XMLNode* node = find_named_node (*settings, X_("Buttons"));
790 node = new XMLNode (X_("Buttons"));
797 Editor::add_toplevel_controls (Container& cont)
799 vpacker.pack_start (cont, false, false);
804 Editor::catch_vanishing_regionview (RegionView *rv)
806 /* note: the selection will take care of the vanishing
807 audioregionview by itself.
810 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
814 if (clicked_regionview == rv) {
815 clicked_regionview = 0;
818 if (entered_regionview == rv) {
819 set_entered_regionview (0);
822 if (!_all_region_actions_sensitized) {
823 sensitize_all_region_actions (true);
826 _over_region_trim_target = false;
830 Editor::set_entered_regionview (RegionView* rv)
832 if (rv == entered_regionview) {
836 if (entered_regionview) {
837 entered_regionview->exited ();
840 if ((entered_regionview = rv) != 0) {
841 entered_regionview->entered (internal_editing ());
844 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
845 /* This RegionView entry might have changed what region actions
846 are allowed, so sensitize them all in case a key is pressed.
848 sensitize_all_region_actions (true);
853 Editor::set_entered_track (TimeAxisView* tav)
856 entered_track->exited ();
859 if ((entered_track = tav) != 0) {
860 entered_track->entered ();
865 Editor::show_window ()
867 if (!is_visible ()) {
870 /* XXX: this is a bit unfortunate; it would probably
871 be nicer if we could just call show () above rather
872 than needing the show_all ()
875 /* re-hide stuff if necessary */
876 editor_list_button_toggled ();
877 parameter_changed ("show-summary");
878 parameter_changed ("show-group-tabs");
879 parameter_changed ("show-zoom-tools");
881 /* now reset all audio_time_axis heights, because widgets might need
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
888 tv = (static_cast<TimeAxisView*>(*i));
892 if (current_mixer_strip) {
893 current_mixer_strip->hide_things ();
894 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
902 Editor::instant_save ()
904 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
909 _session->add_instant_xml(get_state());
911 Config->add_instant_xml(get_state());
916 Editor::zoom_adjustment_changed ()
922 double fpu = zoom_range_clock->current_duration() / _canvas_width;
923 bool clamped = clamp_frames_per_unit (fpu);
926 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
933 Editor::control_vertical_zoom_in_all ()
935 tav_zoom_smooth (false, true);
939 Editor::control_vertical_zoom_out_all ()
941 tav_zoom_smooth (true, true);
945 Editor::control_vertical_zoom_in_selected ()
947 tav_zoom_smooth (false, false);
951 Editor::control_vertical_zoom_out_selected ()
953 tav_zoom_smooth (true, false);
957 Editor::control_view (uint32_t view)
959 goto_visual_state (view);
963 Editor::control_unselect ()
965 selection->clear_tracks ();
969 Editor::control_select (uint32_t rid, Selection::Operation op)
971 /* handles the (static) signal from the ControlProtocol class that
972 * requests setting the selected track to a given RID
979 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
985 TimeAxisView* tav = axis_view_from_route (r);
990 selection->add (tav);
992 case Selection::Toggle:
993 selection->toggle (tav);
995 case Selection::Extend:
998 selection->set (tav);
1002 selection->clear_tracks ();
1007 Editor::control_step_tracks_up ()
1009 scroll_tracks_up_line ();
1013 Editor::control_step_tracks_down ()
1015 scroll_tracks_down_line ();
1019 Editor::control_scroll (float fraction)
1021 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1027 double step = fraction * current_page_frames();
1030 _control_scroll_target is an optional<T>
1032 it acts like a pointer to an framepos_t, with
1033 a operator conversion to boolean to check
1034 that it has a value could possibly use
1035 playhead_cursor->current_frame to store the
1036 value and a boolean in the class to know
1037 when it's out of date
1040 if (!_control_scroll_target) {
1041 _control_scroll_target = _session->transport_frame();
1042 _dragging_playhead = true;
1045 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1046 *_control_scroll_target = 0;
1047 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1048 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1050 *_control_scroll_target += (framepos_t) floor (step);
1053 /* move visuals, we'll catch up with it later */
1055 playhead_cursor->set_position (*_control_scroll_target);
1056 UpdateAllTransportClocks (*_control_scroll_target);
1058 if (*_control_scroll_target > (current_page_frames() / 2)) {
1059 /* try to center PH in window */
1060 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1066 Now we do a timeout to actually bring the session to the right place
1067 according to the playhead. This is to avoid reading disk buffers on every
1068 call to control_scroll, which is driven by ScrollTimeline and therefore
1069 probably by a control surface wheel which can generate lots of events.
1071 /* cancel the existing timeout */
1073 control_scroll_connection.disconnect ();
1075 /* add the next timeout */
1077 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1081 Editor::deferred_control_scroll (framepos_t /*target*/)
1083 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1084 // reset for next stream
1085 _control_scroll_target = boost::none;
1086 _dragging_playhead = false;
1091 Editor::access_action (std::string action_group, std::string action_item)
1097 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1100 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1108 Editor::on_realize ()
1110 Window::on_realize ();
1115 Editor::map_position_change (framepos_t frame)
1117 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1119 if (_session == 0) {
1123 if (_follow_playhead) {
1124 center_screen (frame);
1127 playhead_cursor->set_position (frame);
1131 Editor::center_screen (framepos_t frame)
1133 double page = _canvas_width * frames_per_unit;
1135 /* if we're off the page, then scroll.
1138 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1139 center_screen_internal (frame, page);
1144 Editor::center_screen_internal (framepos_t frame, float page)
1149 frame -= (framepos_t) page;
1154 reset_x_origin (frame);
1159 Editor::update_title ()
1161 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1164 bool dirty = _session->dirty();
1166 string session_name;
1168 if (_session->snap_name() != _session->name()) {
1169 session_name = _session->snap_name();
1171 session_name = _session->name();
1175 session_name = "*" + session_name;
1178 WindowTitle title(session_name);
1179 title += Glib::get_application_name();
1180 set_title (title.get_string());
1182 /* ::session_going_away() will have taken care of it */
1187 Editor::set_session (Session *t)
1189 SessionHandlePtr::set_session (t);
1195 zoom_range_clock->set_session (_session);
1196 _playlist_selector->set_session (_session);
1197 nudge_clock->set_session (_session);
1198 _summary->set_session (_session);
1199 _group_tabs->set_session (_session);
1200 _route_groups->set_session (_session);
1201 _regions->set_session (_session);
1202 _snapshots->set_session (_session);
1203 _routes->set_session (_session);
1204 _locations->set_session (_session);
1206 if (rhythm_ferret) {
1207 rhythm_ferret->set_session (_session);
1210 if (analysis_window) {
1211 analysis_window->set_session (_session);
1215 sfbrowser->set_session (_session);
1218 compute_fixed_ruler_scale ();
1220 /* Make sure we have auto loop and auto punch ranges */
1222 Location* loc = _session->locations()->auto_loop_location();
1224 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1226 if (loc->start() == loc->end()) {
1227 loc->set_end (loc->start() + 1);
1230 _session->locations()->add (loc, false);
1231 _session->set_auto_loop_location (loc);
1234 loc->set_name (_("Loop"));
1237 loc = _session->locations()->auto_punch_location();
1240 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1242 if (loc->start() == loc->end()) {
1243 loc->set_end (loc->start() + 1);
1246 _session->locations()->add (loc, false);
1247 _session->set_auto_punch_location (loc);
1250 loc->set_name (_("Punch"));
1253 refresh_location_display ();
1255 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1256 the selected Marker; this needs the LocationMarker list to be available.
1258 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1259 set_state (*node, Stateful::loading_state_version);
1261 /* catch up with the playhead */
1263 _session->request_locate (playhead_cursor->current_frame);
1264 _pending_initial_locate = true;
1268 /* These signals can all be emitted by a non-GUI thread. Therefore the
1269 handlers for them must not attempt to directly interact with the GUI,
1270 but use Gtkmm2ext::UI::instance()->call_slot();
1273 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1274 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1275 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1276 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1277 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1278 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1279 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1280 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1281 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1282 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1283 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1284 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1285 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1288 playhead_cursor->canvas_item.show ();
1290 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1291 Config->map_parameters (pc);
1292 _session->config.map_parameters (pc);
1294 restore_ruler_visibility ();
1295 //tempo_map_changed (PropertyChange (0));
1296 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1298 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1299 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1302 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1303 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1306 switch (_snap_type) {
1307 case SnapToRegionStart:
1308 case SnapToRegionEnd:
1309 case SnapToRegionSync:
1310 case SnapToRegionBoundary:
1311 build_region_boundary_cache ();
1318 /* register for undo history */
1319 _session->register_with_memento_command_factory(id(), this);
1321 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1323 start_updating_meters ();
1327 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1329 if (a->get_name() == "RegionMenu") {
1330 /* When the main menu's region menu is opened, we setup the actions so that they look right
1331 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1332 so we resensitize all region actions when the entered regionview or the region selection
1333 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1334 happens after the region context menu is opened. So we set a flag here, too.
1338 sensitize_the_right_region_actions ();
1339 _last_region_menu_was_main = true;
1344 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1346 using namespace Menu_Helpers;
1348 void (Editor::*emf)(FadeShape);
1349 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1352 images = &_xfade_in_images;
1353 emf = &Editor::set_fade_in_shape;
1355 images = &_xfade_out_images;
1356 emf = &Editor::set_fade_out_shape;
1361 _("Linear (for highly correlated material)"),
1362 *(*images)[FadeLinear],
1363 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1367 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1372 *(*images)[FadeConstantPower],
1373 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1376 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1381 *(*images)[FadeSymmetric],
1382 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *(*images)[FadeSlow],
1392 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *(*images)[FadeFast],
1401 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1407 /** Pop up a context menu for when the user clicks on a start crossfade */
1409 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1411 using namespace Menu_Helpers;
1413 MenuList& items (xfade_in_context_menu.items());
1415 if (items.empty()) {
1416 fill_xfade_menu (items, true);
1419 xfade_in_context_menu.popup (button, time);
1422 /** Pop up a context menu for when the user clicks on an end crossfade */
1424 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1426 using namespace Menu_Helpers;
1428 MenuList& items (xfade_out_context_menu.items());
1430 if (items.empty()) {
1431 fill_xfade_menu (items, false);
1434 xfade_out_context_menu.popup (button, time);
1438 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1440 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1442 using namespace Menu_Helpers;
1443 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1446 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1450 MenuList& items (fade_context_menu.items());
1453 switch (item_type) {
1455 case FadeInHandleItem:
1456 if (arv->audio_region()->fade_in_active()) {
1457 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1459 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1462 items.push_back (SeparatorElem());
1464 if (Profile->get_sae()) {
1466 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1467 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1474 *_fade_in_images[FadeLinear],
1475 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *_fade_in_images[FadeSlow],
1485 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 *_fade_in_images[FadeFast],
1494 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *_fade_in_images[FadeSymmetric],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1508 _("Constant Power"),
1509 *_fade_in_images[FadeConstantPower],
1510 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 case FadeOutHandleItem:
1520 if (arv->audio_region()->fade_out_active()) {
1521 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1523 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1526 items.push_back (SeparatorElem());
1528 if (Profile->get_sae()) {
1529 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1530 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1536 *_fade_out_images[FadeLinear],
1537 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1541 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1546 *_fade_out_images[FadeSlow],
1547 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1550 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1555 *_fade_out_images[FadeFast],
1556 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1559 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1564 *_fade_out_images[FadeSymmetric],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1570 _("Constant Power"),
1571 *_fade_out_images[FadeConstantPower],
1572 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1575 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1581 fatal << _("programming error: ")
1582 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1587 fade_context_menu.popup (button, time);
1591 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1593 using namespace Menu_Helpers;
1594 Menu* (Editor::*build_menu_function)();
1597 switch (item_type) {
1599 case RegionViewName:
1600 case RegionViewNameHighlight:
1601 case LeftFrameHandle:
1602 case RightFrameHandle:
1603 if (with_selection) {
1604 build_menu_function = &Editor::build_track_selection_context_menu;
1606 build_menu_function = &Editor::build_track_region_context_menu;
1611 if (with_selection) {
1612 build_menu_function = &Editor::build_track_selection_context_menu;
1614 build_menu_function = &Editor::build_track_context_menu;
1619 if (clicked_routeview->track()) {
1620 build_menu_function = &Editor::build_track_context_menu;
1622 build_menu_function = &Editor::build_track_bus_context_menu;
1627 /* probably shouldn't happen but if it does, we don't care */
1631 menu = (this->*build_menu_function)();
1632 menu->set_name ("ArdourContextMenu");
1634 /* now handle specific situations */
1636 switch (item_type) {
1638 case RegionViewName:
1639 case RegionViewNameHighlight:
1640 case LeftFrameHandle:
1641 case RightFrameHandle:
1642 if (!with_selection) {
1643 if (region_edit_menu_split_item) {
1644 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1645 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1647 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1650 if (region_edit_menu_split_multichannel_item) {
1651 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1652 region_edit_menu_split_multichannel_item->set_sensitive (true);
1654 region_edit_menu_split_multichannel_item->set_sensitive (false);
1667 /* probably shouldn't happen but if it does, we don't care */
1671 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1673 /* Bounce to disk */
1675 using namespace Menu_Helpers;
1676 MenuList& edit_items = menu->items();
1678 edit_items.push_back (SeparatorElem());
1680 switch (clicked_routeview->audio_track()->freeze_state()) {
1681 case AudioTrack::NoFreeze:
1682 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1685 case AudioTrack::Frozen:
1686 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1689 case AudioTrack::UnFrozen:
1690 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1696 if (item_type == StreamItem && clicked_routeview) {
1697 clicked_routeview->build_underlay_menu(menu);
1700 /* When the region menu is opened, we setup the actions so that they look right
1703 sensitize_the_right_region_actions ();
1704 _last_region_menu_was_main = false;
1706 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1707 menu->popup (button, time);
1711 Editor::build_track_context_menu ()
1713 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_context_menu.items();
1718 add_dstream_context_items (edit_items);
1719 return &track_context_menu;
1723 Editor::build_track_bus_context_menu ()
1725 using namespace Menu_Helpers;
1727 MenuList& edit_items = track_context_menu.items();
1730 add_bus_context_items (edit_items);
1731 return &track_context_menu;
1735 Editor::build_track_region_context_menu ()
1737 using namespace Menu_Helpers;
1738 MenuList& edit_items = track_region_context_menu.items();
1741 /* we've just cleared the track region context menu, so the menu that these
1742 two items were on will have disappeared; stop them dangling.
1744 region_edit_menu_split_item = 0;
1745 region_edit_menu_split_multichannel_item = 0;
1747 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1750 boost::shared_ptr<Track> tr;
1751 boost::shared_ptr<Playlist> pl;
1753 if ((tr = rtv->track())) {
1754 add_region_context_items (edit_items, tr);
1758 add_dstream_context_items (edit_items);
1760 return &track_region_context_menu;
1764 Editor::analyze_region_selection ()
1766 if (analysis_window == 0) {
1767 analysis_window = new AnalysisWindow();
1770 analysis_window->set_session(_session);
1772 analysis_window->show_all();
1775 analysis_window->set_regionmode();
1776 analysis_window->analyze();
1778 analysis_window->present();
1782 Editor::analyze_range_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_rangemode();
1794 analysis_window->analyze();
1796 analysis_window->present();
1800 Editor::build_track_selection_context_menu ()
1802 using namespace Menu_Helpers;
1803 MenuList& edit_items = track_selection_context_menu.items();
1804 edit_items.clear ();
1806 add_selection_context_items (edit_items);
1807 // edit_items.push_back (SeparatorElem());
1808 // add_dstream_context_items (edit_items);
1810 return &track_selection_context_menu;
1814 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1816 using namespace Menu_Helpers;
1818 /* OK, stick the region submenu at the top of the list, and then add
1822 RegionSelection rs = get_regions_from_selection_and_entered ();
1824 string::size_type pos = 0;
1825 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1827 /* we have to hack up the region name because "_" has a special
1828 meaning for menu titles.
1831 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1832 menu_item_name.replace (pos, 1, "__");
1836 if (_popup_region_menu_item == 0) {
1837 _popup_region_menu_item = new MenuItem (menu_item_name);
1838 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1839 _popup_region_menu_item->show ();
1841 _popup_region_menu_item->set_label (menu_item_name);
1844 const framepos_t position = get_preferred_edit_position (false, true);
1846 edit_items.push_back (*_popup_region_menu_item);
1847 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1848 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1850 edit_items.push_back (SeparatorElem());
1853 /** Add context menu items relevant to selection ranges.
1854 * @param edit_items List to add the items to.
1857 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1859 using namespace Menu_Helpers;
1861 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1862 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1864 edit_items.push_back (SeparatorElem());
1865 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1867 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (
1871 _("Move Range Start to Previous Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1876 edit_items.push_back (
1878 _("Move Range Start to Next Region Boundary"),
1879 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1883 edit_items.push_back (
1885 _("Move Range End to Previous Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1890 edit_items.push_back (
1892 _("Move Range End to Next Region Boundary"),
1893 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1897 edit_items.push_back (SeparatorElem());
1898 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1899 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1901 edit_items.push_back (SeparatorElem());
1902 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1904 edit_items.push_back (SeparatorElem());
1905 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1906 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1913 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1914 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1916 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1918 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1919 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1920 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1921 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1926 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1928 using namespace Menu_Helpers;
1932 Menu *play_menu = manage (new Menu);
1933 MenuList& play_items = play_menu->items();
1934 play_menu->set_name ("ArdourContextMenu");
1936 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1937 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1938 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1939 play_items.push_back (SeparatorElem());
1940 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1942 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1946 Menu *select_menu = manage (new Menu);
1947 MenuList& select_items = select_menu->items();
1948 select_menu->set_name ("ArdourContextMenu");
1950 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1951 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1952 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1953 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1954 select_items.push_back (SeparatorElem());
1955 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1956 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1957 select_items.push_back (SeparatorElem());
1958 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1959 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1960 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1961 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1962 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1963 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1964 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1966 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1970 Menu *cutnpaste_menu = manage (new Menu);
1971 MenuList& cutnpaste_items = cutnpaste_menu->items();
1972 cutnpaste_menu->set_name ("ArdourContextMenu");
1974 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1975 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1976 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1978 cutnpaste_items.push_back (SeparatorElem());
1980 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1981 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1983 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1985 /* Adding new material */
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1989 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1993 Menu *nudge_menu = manage (new Menu());
1994 MenuList& nudge_items = nudge_menu->items();
1995 nudge_menu->set_name ("ArdourContextMenu");
1997 edit_items.push_back (SeparatorElem());
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2003 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2007 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2009 using namespace Menu_Helpers;
2013 Menu *play_menu = manage (new Menu);
2014 MenuList& play_items = play_menu->items();
2015 play_menu->set_name ("ArdourContextMenu");
2017 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2018 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2019 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2023 Menu *select_menu = manage (new Menu);
2024 MenuList& select_items = select_menu->items();
2025 select_menu->set_name ("ArdourContextMenu");
2027 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2028 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2029 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2030 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2031 select_items.push_back (SeparatorElem());
2032 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2033 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2034 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2035 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2037 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2041 Menu *cutnpaste_menu = manage (new Menu);
2042 MenuList& cutnpaste_items = cutnpaste_menu->items();
2043 cutnpaste_menu->set_name ("ArdourContextMenu");
2045 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2046 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2047 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2049 Menu *nudge_menu = manage (new Menu());
2050 MenuList& nudge_items = nudge_menu->items();
2051 nudge_menu->set_name ("ArdourContextMenu");
2053 edit_items.push_back (SeparatorElem());
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2057 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2059 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2063 Editor::snap_type() const
2069 Editor::snap_mode() const
2075 Editor::set_snap_to (SnapType st)
2077 unsigned int snap_ind = (unsigned int)st;
2081 if (snap_ind > snap_type_strings.size() - 1) {
2083 _snap_type = (SnapType)snap_ind;
2086 string str = snap_type_strings[snap_ind];
2088 if (str != snap_type_selector.get_active_text()) {
2089 snap_type_selector.set_active_text (str);
2094 switch (_snap_type) {
2095 case SnapToBeatDiv128:
2096 case SnapToBeatDiv64:
2097 case SnapToBeatDiv32:
2098 case SnapToBeatDiv28:
2099 case SnapToBeatDiv24:
2100 case SnapToBeatDiv20:
2101 case SnapToBeatDiv16:
2102 case SnapToBeatDiv14:
2103 case SnapToBeatDiv12:
2104 case SnapToBeatDiv10:
2105 case SnapToBeatDiv8:
2106 case SnapToBeatDiv7:
2107 case SnapToBeatDiv6:
2108 case SnapToBeatDiv5:
2109 case SnapToBeatDiv4:
2110 case SnapToBeatDiv3:
2111 case SnapToBeatDiv2:
2112 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2113 update_tempo_based_rulers ();
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 SnapChanged (); /* EMIT SIGNAL */
2132 Editor::set_snap_mode (SnapMode mode)
2135 string str = snap_mode_strings[(int)mode];
2137 if (str != snap_mode_selector.get_active_text ()) {
2138 snap_mode_selector.set_active_text (str);
2144 Editor::set_edit_point_preference (EditPoint ep, bool force)
2146 bool changed = (_edit_point != ep);
2149 string str = edit_point_strings[(int)ep];
2151 if (str != edit_point_selector.get_active_text ()) {
2152 edit_point_selector.set_active_text (str);
2155 set_canvas_cursor ();
2157 if (!force && !changed) {
2161 const char* action=NULL;
2163 switch (_edit_point) {
2164 case EditAtPlayhead:
2165 action = "edit-at-playhead";
2167 case EditAtSelectedMarker:
2168 action = "edit-at-marker";
2171 action = "edit-at-mouse";
2175 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2177 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2181 bool in_track_canvas;
2183 if (!mouse_frame (foo, in_track_canvas)) {
2184 in_track_canvas = false;
2187 reset_canvas_action_sensitivity (in_track_canvas);
2193 Editor::set_state (const XMLNode& node, int /*version*/)
2195 const XMLProperty* prop;
2202 g.base_width = default_width;
2203 g.base_height = default_height;
2207 if ((geometry = find_named_node (node, "geometry")) != 0) {
2211 if ((prop = geometry->property("x_size")) == 0) {
2212 prop = geometry->property ("x-size");
2215 g.base_width = atoi(prop->value());
2217 if ((prop = geometry->property("y_size")) == 0) {
2218 prop = geometry->property ("y-size");
2221 g.base_height = atoi(prop->value());
2224 if ((prop = geometry->property ("x_pos")) == 0) {
2225 prop = geometry->property ("x-pos");
2228 x = atoi (prop->value());
2231 if ((prop = geometry->property ("y_pos")) == 0) {
2232 prop = geometry->property ("y-pos");
2235 y = atoi (prop->value());
2239 set_default_size (g.base_width, g.base_height);
2242 if (_session && (prop = node.property ("playhead"))) {
2244 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2245 playhead_cursor->set_position (pos);
2247 playhead_cursor->set_position (0);
2250 if ((prop = node.property ("mixer-width"))) {
2251 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2254 if ((prop = node.property ("zoom-focus"))) {
2255 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2258 if ((prop = node.property ("zoom"))) {
2259 reset_zoom (PBD::atof (prop->value()));
2261 reset_zoom (frames_per_unit);
2264 if ((prop = node.property ("snap-to"))) {
2265 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2268 if ((prop = node.property ("snap-mode"))) {
2269 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2272 if ((prop = node.property ("internal-snap-to"))) {
2273 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2276 if ((prop = node.property ("internal-snap-mode"))) {
2277 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2280 if ((prop = node.property ("pre-internal-snap-to"))) {
2281 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2284 if ((prop = node.property ("pre-internal-snap-mode"))) {
2285 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2288 if ((prop = node.property ("mouse-mode"))) {
2289 MouseMode m = str2mousemode(prop->value());
2290 set_mouse_mode (m, true);
2292 set_mouse_mode (MouseObject, true);
2295 if ((prop = node.property ("left-frame")) != 0) {
2297 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2301 reset_x_origin (pos);
2305 if ((prop = node.property ("y-origin")) != 0) {
2306 reset_y_origin (atof (prop->value ()));
2309 if ((prop = node.property ("internal-edit"))) {
2310 bool yn = string_is_affirmative (prop->value());
2311 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 tact->set_active (!yn);
2315 tact->set_active (yn);
2319 if ((prop = node.property ("join-object-range"))) {
2320 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2323 if ((prop = node.property ("edit-point"))) {
2324 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2327 if ((prop = node.property ("show-measures"))) {
2328 bool yn = string_is_affirmative (prop->value());
2329 _show_measures = yn;
2330 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2332 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2333 /* do it twice to force the change */
2334 tact->set_active (!yn);
2335 tact->set_active (yn);
2339 if ((prop = node.property ("follow-playhead"))) {
2340 bool yn = string_is_affirmative (prop->value());
2341 set_follow_playhead (yn);
2342 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2344 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2345 if (tact->get_active() != yn) {
2346 tact->set_active (yn);
2351 if ((prop = node.property ("stationary-playhead"))) {
2352 bool yn = string_is_affirmative (prop->value());
2353 set_stationary_playhead (yn);
2354 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2356 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2357 if (tact->get_active() != yn) {
2358 tact->set_active (yn);
2363 if ((prop = node.property ("region-list-sort-type"))) {
2364 RegionListSortType st;
2365 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2368 if ((prop = node.property ("show-editor-mixer"))) {
2370 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2373 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2374 bool yn = string_is_affirmative (prop->value());
2376 /* do it twice to force the change */
2378 tact->set_active (!yn);
2379 tact->set_active (yn);
2382 if ((prop = node.property ("show-editor-list"))) {
2384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2388 bool yn = string_is_affirmative (prop->value());
2390 /* do it twice to force the change */
2392 tact->set_active (!yn);
2393 tact->set_active (yn);
2396 if ((prop = node.property (X_("editor-list-page")))) {
2397 _the_notebook.set_current_page (atoi (prop->value ()));
2400 if ((prop = node.property (X_("show-marker-lines")))) {
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2403 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2404 bool yn = string_is_affirmative (prop->value ());
2406 tact->set_active (!yn);
2407 tact->set_active (yn);
2410 XMLNodeList children = node.children ();
2411 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2412 selection->set_state (**i, Stateful::current_state_version);
2413 _regions->set_state (**i);
2416 if ((prop = node.property ("maximised"))) {
2417 bool yn = string_is_affirmative (prop->value());
2419 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2423 if ((prop = node.property ("nudge-clock-value"))) {
2425 sscanf (prop->value().c_str(), "%" PRId64, &f);
2426 nudge_clock->set (f);
2428 nudge_clock->set_mode (AudioClock::Timecode);
2429 nudge_clock->set (_session->frame_rate() * 5, true);
2436 Editor::get_state ()
2438 XMLNode* node = new XMLNode ("Editor");
2441 id().print (buf, sizeof (buf));
2442 node->add_property ("id", buf);
2444 if (is_realized()) {
2445 Glib::RefPtr<Gdk::Window> win = get_window();
2447 int x, y, width, height;
2448 win->get_root_origin(x, y);
2449 win->get_size(width, height);
2451 XMLNode* geometry = new XMLNode ("geometry");
2453 snprintf(buf, sizeof(buf), "%d", width);
2454 geometry->add_property("x-size", string(buf));
2455 snprintf(buf, sizeof(buf), "%d", height);
2456 geometry->add_property("y-size", string(buf));
2457 snprintf(buf, sizeof(buf), "%d", x);
2458 geometry->add_property("x-pos", string(buf));
2459 snprintf(buf, sizeof(buf), "%d", y);
2460 geometry->add_property("y-pos", string(buf));
2461 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2462 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2463 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2464 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2465 geometry->add_property("edit-vertical-pane-pos", string(buf));
2467 node->add_child_nocopy (*geometry);
2470 maybe_add_mixer_strip_width (*node);
2472 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2473 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2474 node->add_property ("zoom", buf);
2475 node->add_property ("snap-to", enum_2_string (_snap_type));
2476 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2477 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2478 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2479 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2480 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2481 node->add_property ("edit-point", enum_2_string (_edit_point));
2483 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2484 node->add_property ("playhead", buf);
2485 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2486 node->add_property ("left-frame", buf);
2487 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2488 node->add_property ("y-origin", buf);
2490 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2491 node->add_property ("maximised", _maximised ? "yes" : "no");
2492 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2493 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2494 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2495 node->add_property ("mouse-mode", enum2str(mouse_mode));
2496 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2497 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2499 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2501 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2502 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2505 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2507 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2508 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2511 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2512 node->add_property (X_("editor-list-page"), buf);
2514 if (button_bindings) {
2515 XMLNode* bb = new XMLNode (X_("Buttons"));
2516 button_bindings->save (*bb);
2517 node->add_child_nocopy (*bb);
2520 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2522 node->add_child_nocopy (selection->get_state ());
2523 node->add_child_nocopy (_regions->get_state ());
2525 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2526 node->add_property ("nudge-clock-value", buf);
2533 /** @param y y offset from the top of all trackviews.
2534 * @return pair: TimeAxisView that y is over, layer index.
2535 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2536 * in stacked or expanded region display mode, otherwise 0.
2538 std::pair<TimeAxisView *, double>
2539 Editor::trackview_by_y_position (double y)
2541 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2543 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2549 return std::make_pair ( (TimeAxisView *) 0, 0);
2552 /** Snap a position to the grid, if appropriate, taking into account current
2553 * grid settings and also the state of any snap modifier keys that may be pressed.
2554 * @param start Position to snap.
2555 * @param event Event to get current key modifier information from, or 0.
2558 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2560 if (!_session || !event) {
2564 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2565 if (_snap_mode == SnapOff) {
2566 snap_to_internal (start, direction, for_mark);
2569 if (_snap_mode != SnapOff) {
2570 snap_to_internal (start, direction, for_mark);
2576 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2578 if (!_session || _snap_mode == SnapOff) {
2582 snap_to_internal (start, direction, for_mark);
2586 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2588 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2589 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2591 switch (_snap_type) {
2592 case SnapToTimecodeFrame:
2593 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2594 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2596 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2600 case SnapToTimecodeSeconds:
2601 if (_session->config.get_timecode_offset_negative()) {
2602 start += _session->config.get_timecode_offset ();
2604 start -= _session->config.get_timecode_offset ();
2606 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2607 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2609 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2612 if (_session->config.get_timecode_offset_negative()) {
2613 start -= _session->config.get_timecode_offset ();
2615 start += _session->config.get_timecode_offset ();
2619 case SnapToTimecodeMinutes:
2620 if (_session->config.get_timecode_offset_negative()) {
2621 start += _session->config.get_timecode_offset ();
2623 start -= _session->config.get_timecode_offset ();
2625 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2626 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2628 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2630 if (_session->config.get_timecode_offset_negative()) {
2631 start -= _session->config.get_timecode_offset ();
2633 start += _session->config.get_timecode_offset ();
2637 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2643 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2645 const framepos_t one_second = _session->frame_rate();
2646 const framepos_t one_minute = _session->frame_rate() * 60;
2647 framepos_t presnap = start;
2651 switch (_snap_type) {
2652 case SnapToTimecodeFrame:
2653 case SnapToTimecodeSeconds:
2654 case SnapToTimecodeMinutes:
2655 return timecode_snap_to_internal (start, direction, for_mark);
2658 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2659 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2661 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2666 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2667 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2669 start = (framepos_t) floor ((double) start / one_second) * one_second;
2674 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2675 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2677 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2682 start = _session->tempo_map().round_to_bar (start, direction);
2686 start = _session->tempo_map().round_to_beat (start, direction);
2689 case SnapToBeatDiv128:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2692 case SnapToBeatDiv64:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2695 case SnapToBeatDiv32:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2698 case SnapToBeatDiv28:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2701 case SnapToBeatDiv24:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2704 case SnapToBeatDiv20:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2707 case SnapToBeatDiv16:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2710 case SnapToBeatDiv14:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2713 case SnapToBeatDiv12:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2716 case SnapToBeatDiv10:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2719 case SnapToBeatDiv8:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2722 case SnapToBeatDiv7:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2725 case SnapToBeatDiv6:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2728 case SnapToBeatDiv5:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2731 case SnapToBeatDiv4:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2734 case SnapToBeatDiv3:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2737 case SnapToBeatDiv2:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2746 _session->locations()->marks_either_side (start, before, after);
2748 if (before == max_framepos && after == max_framepos) {
2749 /* No marks to snap to, so just don't snap */
2751 } else if (before == max_framepos) {
2753 } else if (after == max_framepos) {
2755 } else if (before != max_framepos && after != max_framepos) {
2756 /* have before and after */
2757 if ((start - before) < (after - start)) {
2766 case SnapToRegionStart:
2767 case SnapToRegionEnd:
2768 case SnapToRegionSync:
2769 case SnapToRegionBoundary:
2770 if (!region_boundary_cache.empty()) {
2772 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2773 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2775 if (direction > 0) {
2776 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2778 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2781 if (next != region_boundary_cache.begin ()) {
2786 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2787 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2789 if (start > (p + n) / 2) {
2798 switch (_snap_mode) {
2804 if (presnap > start) {
2805 if (presnap > (start + unit_to_frame(snap_threshold))) {
2809 } else if (presnap < start) {
2810 if (presnap < (start - unit_to_frame(snap_threshold))) {
2816 /* handled at entry */
2824 Editor::setup_toolbar ()
2826 HBox* mode_box = manage(new HBox);
2827 mode_box->set_border_width (2);
2828 mode_box->set_spacing(4);
2830 HBox* mouse_mode_box = manage (new HBox);
2831 HBox* mouse_mode_hbox1 = manage (new HBox);
2832 HBox* mouse_mode_hbox2 = manage (new HBox);
2833 VBox* mouse_mode_vbox1 = manage (new VBox);
2834 VBox* mouse_mode_vbox2 = manage (new VBox);
2835 Alignment* mouse_mode_align1 = manage (new Alignment);
2836 Alignment* mouse_mode_align2 = manage (new Alignment);
2838 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2839 mouse_mode_size_group->add_widget (mouse_move_button);
2840 mouse_mode_size_group->add_widget (mouse_select_button);
2841 mouse_mode_size_group->add_widget (mouse_zoom_button);
2842 mouse_mode_size_group->add_widget (mouse_gain_button);
2843 mouse_mode_size_group->add_widget (mouse_timefx_button);
2844 mouse_mode_size_group->add_widget (mouse_audition_button);
2845 mouse_mode_size_group->add_widget (mouse_draw_button);
2846 mouse_mode_size_group->add_widget (internal_edit_button);
2848 /* make them just a bit bigger */
2849 mouse_move_button.set_size_request (-1, 25);
2851 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2852 smart_mode_joiner->set_related_action (smart_mode_action);
2854 mouse_mode_hbox2->set_spacing (2);
2855 mouse_mode_box->set_spacing (2);
2857 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2858 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2859 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2860 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2861 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2862 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2863 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2865 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2866 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2868 mouse_mode_align1->add (*mouse_mode_vbox1);
2869 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2870 mouse_mode_align2->add (*mouse_mode_vbox2);
2871 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2873 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2874 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2876 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2877 if (!Profile->get_sae()) {
2878 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2880 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2882 edit_mode_selector.set_name ("EditModeSelector");
2883 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2884 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2886 mode_box->pack_start (edit_mode_selector, false, false);
2887 mode_box->pack_start (*mouse_mode_box, false, false);
2889 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2890 _mouse_mode_tearoff->set_name ("MouseModeBase");
2891 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2893 if (Profile->get_sae()) {
2894 _mouse_mode_tearoff->set_can_be_torn_off (false);
2897 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2898 &_mouse_mode_tearoff->tearoff_window()));
2899 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2900 &_mouse_mode_tearoff->tearoff_window(), 1));
2901 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window()));
2903 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window(), 1));
2908 _zoom_box.set_spacing (2);
2909 _zoom_box.set_border_width (2);
2913 zoom_in_button.set_name ("zoom button");
2914 zoom_in_button.set_image (::get_icon ("zoom_in"));
2915 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2916 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2917 zoom_in_button.set_related_action (act);
2919 zoom_out_button.set_name ("zoom button");
2920 zoom_out_button.set_image (::get_icon ("zoom_out"));
2921 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2922 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2923 zoom_out_button.set_related_action (act);
2925 zoom_out_full_button.set_name ("zoom button");
2926 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2927 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2928 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2929 zoom_out_full_button.set_related_action (act);
2931 zoom_focus_selector.set_name ("ZoomFocusSelector");
2932 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2933 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2935 _zoom_box.pack_start (zoom_out_button, false, false);
2936 _zoom_box.pack_start (zoom_in_button, false, false);
2937 _zoom_box.pack_start (zoom_out_full_button, false, false);
2939 _zoom_box.pack_start (zoom_focus_selector, false, false);
2941 /* Track zoom buttons */
2942 tav_expand_button.set_name ("TrackHeightButton");
2943 tav_expand_button.set_size_request (-1, 20);
2944 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2945 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2946 act->connect_proxy (tav_expand_button);
2948 tav_shrink_button.set_name ("TrackHeightButton");
2949 tav_shrink_button.set_size_request (-1, 20);
2950 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2951 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2952 act->connect_proxy (tav_shrink_button);
2954 _zoom_box.pack_start (tav_shrink_button);
2955 _zoom_box.pack_start (tav_expand_button);
2957 _zoom_tearoff = manage (new TearOff (_zoom_box));
2959 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window()));
2961 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window(), 0));
2963 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window()));
2965 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2966 &_zoom_tearoff->tearoff_window(), 0));
2968 snap_box.set_spacing (1);
2969 snap_box.set_border_width (2);
2971 snap_type_selector.set_name ("SnapTypeSelector");
2972 set_popdown_strings (snap_type_selector, snap_type_strings);
2973 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2975 snap_mode_selector.set_name ("SnapModeSelector");
2976 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2977 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2979 edit_point_selector.set_name ("EditPointSelector");
2980 set_popdown_strings (edit_point_selector, edit_point_strings);
2981 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2983 snap_box.pack_start (snap_mode_selector, false, false);
2984 snap_box.pack_start (snap_type_selector, false, false);
2985 snap_box.pack_start (edit_point_selector, false, false);
2989 HBox *nudge_box = manage (new HBox);
2990 nudge_box->set_spacing (2);
2991 nudge_box->set_border_width (2);
2993 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2994 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2996 nudge_box->pack_start (nudge_backward_button, false, false);
2997 nudge_box->pack_start (nudge_forward_button, false, false);
2998 nudge_box->pack_start (*nudge_clock, false, false);
3001 /* Pack everything in... */
3003 HBox* hbox = manage (new HBox);
3004 hbox->set_spacing(10);
3006 _tools_tearoff = manage (new TearOff (*hbox));
3007 _tools_tearoff->set_name ("MouseModeBase");
3008 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3010 if (Profile->get_sae()) {
3011 _tools_tearoff->set_can_be_torn_off (false);
3014 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3015 &_tools_tearoff->tearoff_window()));
3016 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3017 &_tools_tearoff->tearoff_window(), 0));
3018 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window()));
3020 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3021 &_tools_tearoff->tearoff_window(), 0));
3023 toolbar_hbox.set_spacing (10);
3024 toolbar_hbox.set_border_width (1);
3026 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3027 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3028 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3030 hbox->pack_start (snap_box, false, false);
3031 if (!Profile->get_small_screen()) {
3032 hbox->pack_start (*nudge_box, false, false);
3034 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3036 hbox->pack_start (panic_box, false, false);
3040 toolbar_base.set_name ("ToolBarBase");
3041 toolbar_base.add (toolbar_hbox);
3043 _toolbar_viewport.add (toolbar_base);
3044 /* stick to the required height but allow width to vary if there's not enough room */
3045 _toolbar_viewport.set_size_request (1, -1);
3047 toolbar_frame.set_shadow_type (SHADOW_OUT);
3048 toolbar_frame.set_name ("BaseFrame");
3049 toolbar_frame.add (_toolbar_viewport);
3053 Editor::setup_tooltips ()
3055 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3056 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3057 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3058 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3059 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3060 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3061 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3062 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3063 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3064 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3065 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3066 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3067 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3068 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3069 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3070 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3071 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3072 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3073 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3074 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3075 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3076 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3077 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3081 Editor::convert_drop_to_paths (
3082 vector<string>& paths,
3083 const RefPtr<Gdk::DragContext>& /*context*/,
3086 const SelectionData& data,
3090 if (_session == 0) {
3094 vector<string> uris = data.get_uris();
3098 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3099 are actually URI lists. So do it by hand.
3102 if (data.get_target() != "text/plain") {
3106 /* Parse the "uri-list" format that Nautilus provides,
3107 where each pathname is delimited by \r\n.
3109 THERE MAY BE NO NULL TERMINATING CHAR!!!
3112 string txt = data.get_text();
3116 p = (const char *) malloc (txt.length() + 1);
3117 txt.copy (const_cast<char *> (p), txt.length(), 0);
3118 const_cast<char*>(p)[txt.length()] = '\0';
3124 while (g_ascii_isspace (*p))
3128 while (*q && (*q != '\n') && (*q != '\r')) {
3135 while (q > p && g_ascii_isspace (*q))
3140 uris.push_back (string (p, q - p + 1));
3144 p = strchr (p, '\n');
3156 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3158 if ((*i).substr (0,7) == "file://") {
3160 string const p = PBD::url_decode (*i);
3162 // scan forward past three slashes
3164 string::size_type slashcnt = 0;
3165 string::size_type n = 0;
3166 string::const_iterator x = p.begin();
3168 while (slashcnt < 3 && x != p.end()) {
3171 } else if (slashcnt == 3) {
3178 if (slashcnt != 3 || x == p.end()) {
3179 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3183 paths.push_back (p.substr (n - 1));
3191 Editor::new_tempo_section ()
3197 Editor::map_transport_state ()
3199 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3201 if (_session && _session->transport_stopped()) {
3202 have_pending_keyboard_selection = false;
3205 update_loop_range_view (true);
3211 Editor::begin_reversible_command (string name)
3214 _session->begin_reversible_command (name);
3219 Editor::begin_reversible_command (GQuark q)
3222 _session->begin_reversible_command (q);
3227 Editor::commit_reversible_command ()
3230 _session->commit_reversible_command ();
3235 Editor::history_changed ()
3239 if (undo_action && _session) {
3240 if (_session->undo_depth() == 0) {
3241 label = S_("Command|Undo");
3243 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3245 undo_action->property_label() = label;
3248 if (redo_action && _session) {
3249 if (_session->redo_depth() == 0) {
3252 label = string_compose(_("Redo (%1)"), _session->next_redo());
3254 redo_action->property_label() = label;
3259 Editor::duplicate_range (bool with_dialog)
3263 if (mouse_mode == MouseRange) {
3264 if (selection->time.length() == 0) {
3269 RegionSelection rs = get_regions_from_selection_and_entered ();
3271 if (mouse_mode != MouseRange && rs.empty()) {
3277 ArdourDialog win (_("Duplicate"));
3278 Label label (_("Number of duplications:"));
3279 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3280 SpinButton spinner (adjustment, 0.0, 1);
3283 win.get_vbox()->set_spacing (12);
3284 win.get_vbox()->pack_start (hbox);
3285 hbox.set_border_width (6);
3286 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3288 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3289 place, visually. so do this by hand.
3292 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3293 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3294 spinner.grab_focus();
3300 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3301 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3302 win.set_default_response (RESPONSE_ACCEPT);
3304 win.set_position (WIN_POS_MOUSE);
3306 spinner.grab_focus ();
3308 switch (win.run ()) {
3309 case RESPONSE_ACCEPT:
3315 times = adjustment.get_value();
3318 if (mouse_mode == MouseRange) {
3319 duplicate_selection (times);
3321 duplicate_some_regions (rs, times);
3326 Editor::set_edit_mode (EditMode m)
3328 Config->set_edit_mode (m);
3332 Editor::cycle_edit_mode ()
3334 switch (Config->get_edit_mode()) {
3336 if (Profile->get_sae()) {
3337 Config->set_edit_mode (Lock);
3339 Config->set_edit_mode (Splice);
3343 Config->set_edit_mode (Lock);
3346 Config->set_edit_mode (Slide);
3352 Editor::edit_mode_selection_done ()
3354 string s = edit_mode_selector.get_active_text ();
3357 Config->set_edit_mode (string_to_edit_mode (s));
3362 Editor::snap_type_selection_done ()
3364 string choice = snap_type_selector.get_active_text();
3365 SnapType snaptype = SnapToBeat;
3367 if (choice == _("Beats/2")) {
3368 snaptype = SnapToBeatDiv2;
3369 } else if (choice == _("Beats/3")) {
3370 snaptype = SnapToBeatDiv3;
3371 } else if (choice == _("Beats/4")) {
3372 snaptype = SnapToBeatDiv4;
3373 } else if (choice == _("Beats/5")) {
3374 snaptype = SnapToBeatDiv5;
3375 } else if (choice == _("Beats/6")) {
3376 snaptype = SnapToBeatDiv6;
3377 } else if (choice == _("Beats/7")) {
3378 snaptype = SnapToBeatDiv7;
3379 } else if (choice == _("Beats/8")) {
3380 snaptype = SnapToBeatDiv8;
3381 } else if (choice == _("Beats/10")) {
3382 snaptype = SnapToBeatDiv10;
3383 } else if (choice == _("Beats/12")) {
3384 snaptype = SnapToBeatDiv12;
3385 } else if (choice == _("Beats/14")) {
3386 snaptype = SnapToBeatDiv14;
3387 } else if (choice == _("Beats/16")) {
3388 snaptype = SnapToBeatDiv16;
3389 } else if (choice == _("Beats/20")) {
3390 snaptype = SnapToBeatDiv20;
3391 } else if (choice == _("Beats/24")) {
3392 snaptype = SnapToBeatDiv24;
3393 } else if (choice == _("Beats/28")) {
3394 snaptype = SnapToBeatDiv28;
3395 } else if (choice == _("Beats/32")) {
3396 snaptype = SnapToBeatDiv32;
3397 } else if (choice == _("Beats/64")) {
3398 snaptype = SnapToBeatDiv64;
3399 } else if (choice == _("Beats/128")) {
3400 snaptype = SnapToBeatDiv128;
3401 } else if (choice == _("Beats")) {
3402 snaptype = SnapToBeat;
3403 } else if (choice == _("Bars")) {
3404 snaptype = SnapToBar;
3405 } else if (choice == _("Marks")) {
3406 snaptype = SnapToMark;
3407 } else if (choice == _("Region starts")) {
3408 snaptype = SnapToRegionStart;
3409 } else if (choice == _("Region ends")) {
3410 snaptype = SnapToRegionEnd;
3411 } else if (choice == _("Region bounds")) {
3412 snaptype = SnapToRegionBoundary;
3413 } else if (choice == _("Region syncs")) {
3414 snaptype = SnapToRegionSync;
3415 } else if (choice == _("CD Frames")) {
3416 snaptype = SnapToCDFrame;
3417 } else if (choice == _("Timecode Frames")) {
3418 snaptype = SnapToTimecodeFrame;
3419 } else if (choice == _("Timecode Seconds")) {
3420 snaptype = SnapToTimecodeSeconds;
3421 } else if (choice == _("Timecode Minutes")) {
3422 snaptype = SnapToTimecodeMinutes;
3423 } else if (choice == _("Seconds")) {
3424 snaptype = SnapToSeconds;
3425 } else if (choice == _("Minutes")) {
3426 snaptype = SnapToMinutes;
3429 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3431 ract->set_active ();
3436 Editor::snap_mode_selection_done ()
3438 string choice = snap_mode_selector.get_active_text();
3439 SnapMode mode = SnapNormal;
3441 if (choice == _("No Grid")) {
3443 } else if (choice == _("Grid")) {
3445 } else if (choice == _("Magnetic")) {
3446 mode = SnapMagnetic;
3449 RefPtr<RadioAction> ract = snap_mode_action (mode);
3452 ract->set_active (true);
3457 Editor::cycle_edit_point (bool with_marker)
3459 switch (_edit_point) {
3461 set_edit_point_preference (EditAtPlayhead);
3463 case EditAtPlayhead:
3465 set_edit_point_preference (EditAtSelectedMarker);
3467 set_edit_point_preference (EditAtMouse);
3470 case EditAtSelectedMarker:
3471 set_edit_point_preference (EditAtMouse);
3477 Editor::edit_point_selection_done ()
3479 string choice = edit_point_selector.get_active_text();
3480 EditPoint ep = EditAtSelectedMarker;
3482 if (choice == _("Marker")) {
3483 set_edit_point_preference (EditAtSelectedMarker);
3484 } else if (choice == _("Playhead")) {
3485 set_edit_point_preference (EditAtPlayhead);
3487 set_edit_point_preference (EditAtMouse);
3490 RefPtr<RadioAction> ract = edit_point_action (ep);
3493 ract->set_active (true);
3498 Editor::zoom_focus_selection_done ()
3500 string choice = zoom_focus_selector.get_active_text();
3501 ZoomFocus focus_type = ZoomFocusLeft;
3503 if (choice == _("Left")) {
3504 focus_type = ZoomFocusLeft;
3505 } else if (choice == _("Right")) {
3506 focus_type = ZoomFocusRight;
3507 } else if (choice == _("Center")) {
3508 focus_type = ZoomFocusCenter;
3509 } else if (choice == _("Playhead")) {
3510 focus_type = ZoomFocusPlayhead;
3511 } else if (choice == _("Mouse")) {
3512 focus_type = ZoomFocusMouse;
3513 } else if (choice == _("Edit point")) {
3514 focus_type = ZoomFocusEdit;
3517 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3520 ract->set_active ();
3525 Editor::edit_controls_button_release (GdkEventButton* ev)
3527 if (Keyboard::is_context_menu_event (ev)) {
3528 ARDOUR_UI::instance()->add_route (this);
3529 } else if (ev->button == 1) {
3530 selection->clear_tracks ();
3537 Editor::mouse_select_button_release (GdkEventButton* ev)
3539 /* this handles just right-clicks */
3541 if (ev->button != 3) {
3549 Editor::set_zoom_focus (ZoomFocus f)
3551 string str = zoom_focus_strings[(int)f];
3553 if (str != zoom_focus_selector.get_active_text()) {
3554 zoom_focus_selector.set_active_text (str);
3557 if (zoom_focus != f) {
3564 Editor::ensure_float (Window& win)
3566 win.set_transient_for (*this);
3570 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3572 /* recover or initialize pane positions. do this here rather than earlier because
3573 we don't want the positions to change the child allocations, which they seem to do.
3579 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3588 XMLNode* geometry = find_named_node (*node, "geometry");
3590 if (which == static_cast<Paned*> (&edit_pane)) {
3592 if (done & Horizontal) {
3596 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3597 _notebook_shrunk = string_is_affirmative (prop->value ());
3600 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3601 /* initial allocation is 90% to canvas, 10% to notebook */
3602 pos = (int) floor (alloc.get_width() * 0.90f);
3603 snprintf (buf, sizeof(buf), "%d", pos);
3605 pos = atoi (prop->value());
3608 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3609 edit_pane.set_position (pos);
3612 done = (Pane) (done | Horizontal);
3614 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3616 if (done & Vertical) {
3620 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3621 /* initial allocation is 90% to canvas, 10% to summary */
3622 pos = (int) floor (alloc.get_height() * 0.90f);
3623 snprintf (buf, sizeof(buf), "%d", pos);
3626 pos = atoi (prop->value());
3629 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3630 editor_summary_pane.set_position (pos);
3633 done = (Pane) (done | Vertical);
3638 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3640 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3641 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3642 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3643 top_hbox.remove (toolbar_frame);
3648 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3650 if (toolbar_frame.get_parent() == 0) {
3651 top_hbox.pack_end (toolbar_frame);
3656 Editor::set_show_measures (bool yn)
3658 if (_show_measures != yn) {
3661 if ((_show_measures = yn) == true) {
3663 tempo_lines->show();
3671 Editor::toggle_follow_playhead ()
3673 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3675 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3676 set_follow_playhead (tact->get_active());
3680 /** @param yn true to follow playhead, otherwise false.
3681 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3684 Editor::set_follow_playhead (bool yn, bool catch_up)
3686 if (_follow_playhead != yn) {
3687 if ((_follow_playhead = yn) == true && catch_up) {
3689 reset_x_origin_to_follow_playhead ();
3696 Editor::toggle_stationary_playhead ()
3698 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3700 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3701 set_stationary_playhead (tact->get_active());
3706 Editor::set_stationary_playhead (bool yn)
3708 if (_stationary_playhead != yn) {
3709 if ((_stationary_playhead = yn) == true) {
3711 // FIXME need a 3.0 equivalent of this 2.X call
3712 // update_current_screen ();
3719 Editor::playlist_selector () const
3721 return *_playlist_selector;
3725 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3729 switch (_snap_type) {
3734 case SnapToBeatDiv128:
3737 case SnapToBeatDiv64:
3740 case SnapToBeatDiv32:
3743 case SnapToBeatDiv28:
3746 case SnapToBeatDiv24:
3749 case SnapToBeatDiv20:
3752 case SnapToBeatDiv16:
3755 case SnapToBeatDiv14:
3758 case SnapToBeatDiv12:
3761 case SnapToBeatDiv10:
3764 case SnapToBeatDiv8:
3767 case SnapToBeatDiv7:
3770 case SnapToBeatDiv6:
3773 case SnapToBeatDiv5:
3776 case SnapToBeatDiv4:
3779 case SnapToBeatDiv3:
3782 case SnapToBeatDiv2:
3788 return _session->tempo_map().meter_at (position).divisions_per_bar();
3793 case SnapToTimecodeFrame:
3794 case SnapToTimecodeSeconds:
3795 case SnapToTimecodeMinutes:
3798 case SnapToRegionStart:
3799 case SnapToRegionEnd:
3800 case SnapToRegionSync:
3801 case SnapToRegionBoundary:
3811 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3815 ret = nudge_clock->current_duration (pos);
3816 next = ret + 1; /* XXXX fix me */
3822 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3824 ArdourDialog dialog (_("Playlist Deletion"));
3825 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3826 "If it is kept, its audio files will not be cleaned.\n"
3827 "If it is deleted, audio files used by it alone will be cleaned."),
3830 dialog.set_position (WIN_POS_CENTER);
3831 dialog.get_vbox()->pack_start (label);
3835 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3836 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3837 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3839 switch (dialog.run ()) {
3840 case RESPONSE_ACCEPT:
3841 /* delete the playlist */
3845 case RESPONSE_REJECT:
3846 /* keep the playlist */
3858 Editor::audio_region_selection_covers (framepos_t where)
3860 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3861 if ((*a)->region()->covers (where)) {
3870 Editor::prepare_for_cleanup ()
3872 cut_buffer->clear_regions ();
3873 cut_buffer->clear_playlists ();
3875 selection->clear_regions ();
3876 selection->clear_playlists ();
3878 _regions->suspend_redisplay ();
3882 Editor::finish_cleanup ()
3884 _regions->resume_redisplay ();
3888 Editor::transport_loop_location()
3891 return _session->locations()->auto_loop_location();
3898 Editor::transport_punch_location()
3901 return _session->locations()->auto_punch_location();
3908 Editor::control_layout_scroll (GdkEventScroll* ev)
3910 if (Keyboard::some_magic_widget_has_focus()) {
3914 switch (ev->direction) {
3916 scroll_tracks_up_line ();
3920 case GDK_SCROLL_DOWN:
3921 scroll_tracks_down_line ();
3925 /* no left/right handling yet */
3933 Editor::session_state_saved (string)
3936 _snapshots->redisplay ();
3940 Editor::update_tearoff_visibility()
3942 bool visible = Config->get_keep_tearoffs();
3943 _mouse_mode_tearoff->set_visible (visible);
3944 _tools_tearoff->set_visible (visible);
3945 _zoom_tearoff->set_visible (visible);
3949 Editor::maximise_editing_space ()
3961 Editor::restore_editing_space ()
3973 * Make new playlists for a given track and also any others that belong
3974 * to the same active route group with the `edit' property.
3979 Editor::new_playlists (TimeAxisView* v)
3981 begin_reversible_command (_("new playlists"));
3982 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3983 _session->playlists->get (playlists);
3984 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3985 commit_reversible_command ();
3989 * Use a copy of the current playlist for a given track and also any others that belong
3990 * to the same active route group with the `edit' property.
3995 Editor::copy_playlists (TimeAxisView* v)
3997 begin_reversible_command (_("copy playlists"));
3998 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3999 _session->playlists->get (playlists);
4000 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4001 commit_reversible_command ();
4004 /** Clear the current playlist for a given track and also any others that belong
4005 * to the same active route group with the `edit' property.
4010 Editor::clear_playlists (TimeAxisView* v)
4012 begin_reversible_command (_("clear playlists"));
4013 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4014 _session->playlists->get (playlists);
4015 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4016 commit_reversible_command ();
4020 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4022 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4026 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4028 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4032 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4034 atv.clear_playlist ();
4038 Editor::on_key_press_event (GdkEventKey* ev)
4040 return key_press_focus_accelerator_handler (*this, ev);
4044 Editor::on_key_release_event (GdkEventKey* ev)
4046 return Gtk::Window::on_key_release_event (ev);
4047 // return key_press_focus_accelerator_handler (*this, ev);
4050 /** Queue up a change to the viewport x origin.
4051 * @param frame New x origin.
4054 Editor::reset_x_origin (framepos_t frame)
4056 pending_visual_change.add (VisualChange::TimeOrigin);
4057 pending_visual_change.time_origin = frame;
4058 ensure_visual_change_idle_handler ();
4062 Editor::reset_y_origin (double y)
4064 pending_visual_change.add (VisualChange::YOrigin);
4065 pending_visual_change.y_origin = y;
4066 ensure_visual_change_idle_handler ();
4070 Editor::reset_zoom (double fpu)
4072 clamp_frames_per_unit (fpu);
4074 if (fpu == frames_per_unit) {
4078 pending_visual_change.add (VisualChange::ZoomLevel);
4079 pending_visual_change.frames_per_unit = fpu;
4080 ensure_visual_change_idle_handler ();
4084 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4086 reset_x_origin (frame);
4089 if (!no_save_visual) {
4090 undo_visual_stack.push_back (current_visual_state(false));
4094 Editor::VisualState::VisualState (bool with_tracks)
4095 : gui_state (with_tracks ? new GUIObjectState : 0)
4099 Editor::VisualState::~VisualState ()
4104 Editor::VisualState*
4105 Editor::current_visual_state (bool with_tracks)
4107 VisualState* vs = new VisualState (with_tracks);
4108 vs->y_position = vertical_adjustment.get_value();
4109 vs->frames_per_unit = frames_per_unit;
4110 vs->leftmost_frame = leftmost_frame;
4111 vs->zoom_focus = zoom_focus;
4114 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4121 Editor::undo_visual_state ()
4123 if (undo_visual_stack.empty()) {
4127 VisualState* vs = undo_visual_stack.back();
4128 undo_visual_stack.pop_back();
4131 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4133 use_visual_state (*vs);
4137 Editor::redo_visual_state ()
4139 if (redo_visual_stack.empty()) {
4143 VisualState* vs = redo_visual_stack.back();
4144 redo_visual_stack.pop_back();
4146 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4148 use_visual_state (*vs);
4152 Editor::swap_visual_state ()
4154 if (undo_visual_stack.empty()) {
4155 redo_visual_state ();
4157 undo_visual_state ();
4162 Editor::use_visual_state (VisualState& vs)
4164 PBD::Unwinder<bool> nsv (no_save_visual, true);
4166 _routes->suspend_redisplay ();
4168 vertical_adjustment.set_value (vs.y_position);
4170 set_zoom_focus (vs.zoom_focus);
4171 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4174 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4177 (*i)->reset_visual_state ();
4181 _routes->update_visibility ();
4182 _routes->resume_redisplay ();
4185 /** This is the core function that controls the zoom level of the canvas. It is called
4186 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4187 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4190 Editor::set_frames_per_unit (double fpu)
4193 tempo_lines->tempo_map_changed();
4196 frames_per_unit = fpu;
4198 /* convert fpu to frame count */
4200 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4202 if (frames_per_unit != zoom_range_clock->current_duration()) {
4203 zoom_range_clock->set (frames);
4206 bool const showing_time_selection =
4207 mouse_mode == MouseRange ||
4208 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4210 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4211 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4212 (*i)->reshow_selection (selection->time);
4216 ZoomChanged (); /* EMIT_SIGNAL */
4218 //reset_scrolling_region ();
4220 if (playhead_cursor) {
4221 playhead_cursor->set_position (playhead_cursor->current_frame);
4224 refresh_location_display();
4225 _summary->set_overlays_dirty ();
4227 update_marker_labels ();
4233 Editor::ensure_visual_change_idle_handler ()
4235 if (pending_visual_change.idle_handler_id < 0) {
4236 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4241 Editor::_idle_visual_changer (void* arg)
4243 return static_cast<Editor*>(arg)->idle_visual_changer ();
4247 Editor::idle_visual_changer ()
4249 /* set_horizontal_position() below (and maybe other calls) call
4250 gtk_main_iteration(), so it's possible that a signal will be handled
4251 half-way through this method. If this signal wants an
4252 idle_visual_changer we must schedule another one after this one, so
4253 mark the idle_handler_id as -1 here to allow that. Also make a note
4254 that we are doing the visual change, so that changes in response to
4255 super-rapid-screen-update can be dropped if we are still processing
4258 pending_visual_change.idle_handler_id = -1;
4259 pending_visual_change.being_handled = true;
4261 VisualChange::Type p = pending_visual_change.pending;
4262 pending_visual_change.pending = (VisualChange::Type) 0;
4264 double const last_time_origin = horizontal_position ();
4266 if (p & VisualChange::ZoomLevel) {
4267 set_frames_per_unit (pending_visual_change.frames_per_unit);
4269 compute_fixed_ruler_scale ();
4270 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4271 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4272 update_tempo_based_rulers ();
4274 if (p & VisualChange::TimeOrigin) {
4275 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4277 if (p & VisualChange::YOrigin) {
4278 vertical_adjustment.set_value (pending_visual_change.y_origin);
4281 if (last_time_origin == horizontal_position ()) {
4282 /* changed signal not emitted */
4283 update_fixed_rulers ();
4284 redisplay_tempo (true);
4287 _summary->set_overlays_dirty ();
4289 pending_visual_change.being_handled = false;
4290 return 0; /* this is always a one-shot call */
4293 struct EditorOrderTimeAxisSorter {
4294 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4295 return a->order () < b->order ();
4300 Editor::sort_track_selection (TrackViewList& sel)
4302 EditorOrderTimeAxisSorter cmp;
4307 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4310 framepos_t where = 0;
4311 EditPoint ep = _edit_point;
4313 if (from_context_menu && (ep == EditAtMouse)) {
4314 return event_frame (&context_click_event, 0, 0);
4317 if (entered_marker) {
4318 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4319 return entered_marker->position();
4322 if (ignore_playhead && ep == EditAtPlayhead) {
4323 ep = EditAtSelectedMarker;
4327 case EditAtPlayhead:
4328 where = _session->audible_frame();
4329 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4332 case EditAtSelectedMarker:
4333 if (!selection->markers.empty()) {
4335 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4338 where = loc->start();
4342 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4350 if (!mouse_frame (where, ignored)) {
4351 /* XXX not right but what can we do ? */
4355 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4363 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4365 if (!_session) return;
4367 begin_reversible_command (cmd);
4371 if ((tll = transport_loop_location()) == 0) {
4372 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4373 XMLNode &before = _session->locations()->get_state();
4374 _session->locations()->add (loc, true);
4375 _session->set_auto_loop_location (loc);
4376 XMLNode &after = _session->locations()->get_state();
4377 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4379 XMLNode &before = tll->get_state();
4380 tll->set_hidden (false, this);
4381 tll->set (start, end);
4382 XMLNode &after = tll->get_state();
4383 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4386 commit_reversible_command ();
4390 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4392 if (!_session) return;
4394 begin_reversible_command (cmd);
4398 if ((tpl = transport_punch_location()) == 0) {
4399 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4400 XMLNode &before = _session->locations()->get_state();
4401 _session->locations()->add (loc, true);
4402 _session->set_auto_loop_location (loc);
4403 XMLNode &after = _session->locations()->get_state();
4404 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4407 XMLNode &before = tpl->get_state();
4408 tpl->set_hidden (false, this);
4409 tpl->set (start, end);
4410 XMLNode &after = tpl->get_state();
4411 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4414 commit_reversible_command ();
4417 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4418 * @param rs List to which found regions are added.
4419 * @param where Time to look at.
4420 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4423 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4425 const TrackViewList* tracks;
4428 tracks = &track_views;
4433 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4435 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4438 boost::shared_ptr<Track> tr;
4439 boost::shared_ptr<Playlist> pl;
4441 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4443 boost::shared_ptr<RegionList> regions = pl->regions_at (
4444 (framepos_t) floor ( (double) where * tr->speed()));
4446 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4447 RegionView* rv = rtv->view()->find_view (*i);
4458 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4460 const TrackViewList* tracks;
4463 tracks = &track_views;
4468 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4469 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4471 boost::shared_ptr<Track> tr;
4472 boost::shared_ptr<Playlist> pl;
4474 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4476 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4477 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4479 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4481 RegionView* rv = rtv->view()->find_view (*i);
4492 /** Start with regions that are selected. Then add equivalent regions
4493 * on tracks in the same active edit-enabled route group as any of
4494 * the regions that we started with.
4498 Editor::get_regions_from_selection ()
4500 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4503 /** Get regions using the following method:
4505 * Make an initial region list using the selected regions, unless
4506 * the edit point is `mouse' and the mouse is over an unselected
4507 * region. In this case, start with just that region.
4509 * Then, add equivalent regions in active edit groups to the region list.
4511 * Then, search the list of selected tracks to find any selected tracks which
4512 * do not contain regions already in the region list. If there are no selected
4513 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4514 * than just the selected.
4516 * Add any regions that are under the edit point on these tracks to get the
4517 * returned region list.
4519 * The rationale here is that the mouse edit point is special in that
4520 * its position describes both a time and a track; the other edit
4521 * modes only describe a time. Hence if the edit point is `mouse' we
4522 * ignore selected tracks, as we assume the user means something by
4523 * pointing at a particular track. Also in this case we take note of
4524 * the region directly under the edit point, as there is always just one
4525 * (rather than possibly several with non-mouse edit points).
4529 Editor::get_regions_from_selection_and_edit_point ()
4531 RegionSelection regions;
4533 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4534 regions.add (entered_regionview);
4536 regions = selection->regions;
4539 TrackViewList tracks;
4541 if (_edit_point != EditAtMouse) {
4542 tracks = selection->tracks;
4545 /* Add any other regions that are in the same
4546 edit-activated route group as one of our regions.
4548 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4549 framepos_t const where = get_preferred_edit_position ();
4551 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4552 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4553 * is enabled, so consider all tracks
4555 tracks = track_views;
4558 if (!tracks.empty()) {
4559 /* now search the selected tracks for tracks which don't
4560 already contain regions to be acted upon, and get regions at
4561 the edit point on those tracks too.
4563 TrackViewList tracks_without_relevant_regions;
4565 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4566 if (!regions.involves (**t)) {
4567 /* there are no equivalent regions on this track */
4568 tracks_without_relevant_regions.push_back (*t);
4572 if (!tracks_without_relevant_regions.empty()) {
4573 /* there are some selected tracks with neither selected
4574 * regions or their equivalents: act upon all regions in
4577 get_regions_at (regions, where, tracks_without_relevant_regions);
4584 /** Start with regions that are selected, or the entered regionview if none are selected.
4585 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4586 * of the regions that we started with.
4590 Editor::get_regions_from_selection_and_entered ()
4592 RegionSelection regions = selection->regions;
4594 if (regions.empty() && entered_regionview) {
4595 regions.add (entered_regionview);
4598 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4602 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4604 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4606 RouteTimeAxisView* tatv;
4608 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4610 boost::shared_ptr<Playlist> pl;
4611 vector<boost::shared_ptr<Region> > results;
4613 boost::shared_ptr<Track> tr;
4615 if ((tr = tatv->track()) == 0) {
4620 if ((pl = (tr->playlist())) != 0) {
4621 pl->get_region_list_equivalent_regions (region, results);
4624 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4625 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4626 regions.push_back (marv);
4635 Editor::show_rhythm_ferret ()
4637 if (rhythm_ferret == 0) {
4638 rhythm_ferret = new RhythmFerret(*this);
4641 rhythm_ferret->set_session (_session);
4642 rhythm_ferret->show ();
4643 rhythm_ferret->present ();
4647 Editor::first_idle ()
4649 MessageDialog* dialog = 0;
4651 if (track_views.size() > 1) {
4652 dialog = new MessageDialog (
4654 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4658 ARDOUR_UI::instance()->flush_pending ();
4661 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4665 // first idle adds route children (automation tracks), so we need to redisplay here
4666 _routes->redisplay ();
4673 Editor::_idle_resize (gpointer arg)
4675 return ((Editor*)arg)->idle_resize ();
4679 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4681 if (resize_idle_id < 0) {
4682 resize_idle_id = g_idle_add (_idle_resize, this);
4683 _pending_resize_amount = 0;
4686 /* make a note of the smallest resulting height, so that we can clamp the
4687 lower limit at TimeAxisView::hSmall */
4689 int32_t min_resulting = INT32_MAX;
4691 _pending_resize_amount += h;
4692 _pending_resize_view = view;
4694 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4696 if (selection->tracks.contains (_pending_resize_view)) {
4697 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4698 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4702 if (min_resulting < 0) {
4707 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4708 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4712 /** Handle pending resizing of tracks */
4714 Editor::idle_resize ()
4716 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4718 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4719 selection->tracks.contains (_pending_resize_view)) {
4721 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4722 if (*i != _pending_resize_view) {
4723 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4728 _pending_resize_amount = 0;
4730 _group_tabs->set_dirty ();
4731 resize_idle_id = -1;
4739 ENSURE_GUI_THREAD (*this, &Editor::located);
4742 playhead_cursor->set_position (_session->audible_frame ());
4743 if (_follow_playhead && !_pending_initial_locate) {
4744 reset_x_origin_to_follow_playhead ();
4748 _pending_locate_request = false;
4749 _pending_initial_locate = false;
4753 Editor::region_view_added (RegionView *)
4755 _summary->set_dirty ();
4759 Editor::region_view_removed ()
4761 _summary->set_dirty ();
4765 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4767 TrackViewList::const_iterator j = track_views.begin ();
4768 while (j != track_views.end()) {
4769 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4770 if (rtv && rtv->route() == r) {
4781 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4785 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4786 TimeAxisView* tv = axis_view_from_route (*i);
4796 Editor::add_routes (RouteList& routes)
4798 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4800 RouteTimeAxisView *rtv;
4801 list<RouteTimeAxisView*> new_views;
4803 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4804 boost::shared_ptr<Route> route = (*x);
4806 if (route->is_hidden() || route->is_monitor()) {
4810 DataType dt = route->input()->default_type();
4812 if (dt == ARDOUR::DataType::AUDIO) {
4813 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4814 rtv->set_route (route);
4815 } else if (dt == ARDOUR::DataType::MIDI) {
4816 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4817 rtv->set_route (route);
4819 throw unknown_type();
4822 new_views.push_back (rtv);
4823 track_views.push_back (rtv);
4825 rtv->effective_gain_display ();
4827 if (internal_editing()) {
4828 rtv->enter_internal_edit_mode ();
4830 rtv->leave_internal_edit_mode ();
4833 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4834 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4837 _routes->routes_added (new_views);
4838 _summary->routes_added (new_views);
4840 if (show_editor_mixer_when_tracks_arrive) {
4841 show_editor_mixer (true);
4844 editor_list_button.set_sensitive (true);
4848 Editor::timeaxisview_deleted (TimeAxisView *tv)
4850 if (_session && _session->deletion_in_progress()) {
4851 /* the situation is under control */
4855 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4857 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4859 _routes->route_removed (tv);
4861 if (tv == entered_track) {
4865 TimeAxisView::Children c = tv->get_child_list ();
4866 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4867 if (entered_track == i->get()) {
4872 /* remove it from the list of track views */
4874 TrackViewList::iterator i;
4876 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4877 i = track_views.erase (i);
4880 /* update whatever the current mixer strip is displaying, if revelant */
4882 boost::shared_ptr<Route> route;
4885 route = rtav->route ();
4888 if (current_mixer_strip && current_mixer_strip->route() == route) {
4890 TimeAxisView* next_tv;
4892 if (track_views.empty()) {
4894 } else if (i == track_views.end()) {
4895 next_tv = track_views.front();
4902 set_selected_mixer_strip (*next_tv);
4904 /* make the editor mixer strip go away setting the
4905 * button to inactive (which also unticks the menu option)
4908 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4914 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4916 if (apply_to_selection) {
4917 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4919 TrackSelection::iterator j = i;
4922 hide_track_in_display (*i, false);
4927 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4929 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4930 // this will hide the mixer strip
4931 set_selected_mixer_strip (*tv);
4934 _routes->hide_track_in_display (*tv);
4939 Editor::sync_track_view_list_and_routes ()
4941 track_views = TrackViewList (_routes->views ());
4943 _summary->set_dirty ();
4944 _group_tabs->set_dirty ();
4946 return false; // do not call again (until needed)
4950 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4952 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4957 /** Find a RouteTimeAxisView by the ID of its route */
4959 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4961 RouteTimeAxisView* v;
4963 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4964 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4965 if(v->route()->id() == id) {
4975 Editor::fit_route_group (RouteGroup *g)
4977 TrackViewList ts = axis_views_from_routes (g->route_list ());
4982 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4984 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4987 _session->cancel_audition ();
4991 if (_session->is_auditioning()) {
4992 _session->cancel_audition ();
4993 if (r == last_audition_region) {
4998 _session->audition_region (r);
4999 last_audition_region = r;
5004 Editor::hide_a_region (boost::shared_ptr<Region> r)
5006 r->set_hidden (true);
5010 Editor::show_a_region (boost::shared_ptr<Region> r)
5012 r->set_hidden (false);
5016 Editor::audition_region_from_region_list ()
5018 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5022 Editor::hide_region_from_region_list ()
5024 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5028 Editor::show_region_in_region_list ()
5030 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5034 Editor::step_edit_status_change (bool yn)
5037 start_step_editing ();
5039 stop_step_editing ();
5044 Editor::start_step_editing ()
5046 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5050 Editor::stop_step_editing ()
5052 step_edit_connection.disconnect ();
5056 Editor::check_step_edit ()
5058 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5059 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5061 mtv->check_step_edit ();
5065 return true; // do it again, till we stop
5069 Editor::scroll_press (Direction dir)
5071 ++_scroll_callbacks;
5073 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5074 /* delay the first auto-repeat */
5080 scroll_backward (1);
5088 scroll_tracks_up_line ();
5092 scroll_tracks_down_line ();
5096 /* do hacky auto-repeat */
5097 if (!_scroll_connection.connected ()) {
5099 _scroll_connection = Glib::signal_timeout().connect (
5100 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5103 _scroll_callbacks = 0;
5110 Editor::scroll_release ()
5112 _scroll_connection.disconnect ();
5115 /** Queue a change for the Editor viewport x origin to follow the playhead */
5117 Editor::reset_x_origin_to_follow_playhead ()
5119 framepos_t const frame = playhead_cursor->current_frame;
5121 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5123 if (_session->transport_speed() < 0) {
5125 if (frame > (current_page_frames() / 2)) {
5126 center_screen (frame-(current_page_frames()/2));
5128 center_screen (current_page_frames()/2);
5135 if (frame < leftmost_frame) {
5137 if (_session->transport_rolling()) {
5138 /* rolling; end up with the playhead at the right of the page */
5139 l = frame - current_page_frames ();
5141 /* not rolling: end up with the playhead 1/4 of the way along the page */
5142 l = frame - current_page_frames() / 4;
5146 if (_session->transport_rolling()) {
5147 /* rolling: end up with the playhead on the left of the page */
5150 /* not rolling: end up with the playhead 3/4 of the way along the page */
5151 l = frame - 3 * current_page_frames() / 4;
5159 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5165 Editor::super_rapid_screen_update ()
5167 if (!_session || !_session->engine().running()) {
5171 /* METERING / MIXER STRIPS */
5173 /* update track meters, if required */
5174 if (is_mapped() && meters_running) {
5175 RouteTimeAxisView* rtv;
5176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5177 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5178 rtv->fast_update ();
5183 /* and any current mixer strip */
5184 if (current_mixer_strip) {
5185 current_mixer_strip->fast_update ();
5188 /* PLAYHEAD AND VIEWPORT */
5190 framepos_t const frame = _session->audible_frame();
5192 /* There are a few reasons why we might not update the playhead / viewport stuff:
5194 * 1. we don't update things when there's a pending locate request, otherwise
5195 * when the editor requests a locate there is a chance that this method
5196 * will move the playhead before the locate request is processed, causing
5198 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5199 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5202 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5204 last_update_frame = frame;
5206 if (!_dragging_playhead) {
5207 playhead_cursor->set_position (frame);
5210 if (!_stationary_playhead) {
5212 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5213 /* We only do this if we aren't already
5214 handling a visual change (ie if
5215 pending_visual_change.being_handled is
5216 false) so that these requests don't stack
5217 up there are too many of them to handle in
5220 reset_x_origin_to_follow_playhead ();
5225 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5229 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5230 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5231 if (target <= 0.0) {
5234 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5235 target = (target * 0.15) + (current * 0.85);
5241 set_horizontal_position (current);
5250 Editor::session_going_away ()
5252 _have_idled = false;
5254 _session_connections.drop_connections ();
5256 super_rapid_screen_update_connection.disconnect ();
5258 selection->clear ();
5259 cut_buffer->clear ();
5261 clicked_regionview = 0;
5262 clicked_axisview = 0;
5263 clicked_routeview = 0;
5264 entered_regionview = 0;
5266 last_update_frame = 0;
5269 playhead_cursor->canvas_item.hide ();
5271 /* rip everything out of the list displays */
5275 _route_groups->clear ();
5277 /* do this first so that deleting a track doesn't reset cms to null
5278 and thus cause a leak.
5281 if (current_mixer_strip) {
5282 if (current_mixer_strip->get_parent() != 0) {
5283 global_hpacker.remove (*current_mixer_strip);
5285 delete current_mixer_strip;
5286 current_mixer_strip = 0;
5289 /* delete all trackviews */
5291 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5294 track_views.clear ();
5296 zoom_range_clock->set_session (0);
5297 nudge_clock->set_session (0);
5299 editor_list_button.set_active(false);
5300 editor_list_button.set_sensitive(false);
5302 /* clear tempo/meter rulers */
5303 remove_metric_marks ();
5305 clear_marker_display ();
5307 stop_step_editing ();
5309 current_bbt_points_begin = current_bbt_points_end;
5311 /* get rid of any existing editor mixer strip */
5313 WindowTitle title(Glib::get_application_name());
5314 title += _("Editor");
5316 set_title (title.get_string());
5318 SessionHandlePtr::session_going_away ();
5323 Editor::show_editor_list (bool yn)
5326 _the_notebook.show ();
5328 _the_notebook.hide ();
5333 Editor::change_region_layering_order (bool from_context_menu)
5335 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5337 if (!clicked_routeview) {
5338 if (layering_order_editor) {
5339 layering_order_editor->hide ();
5344 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5350 boost::shared_ptr<Playlist> pl = track->playlist();
5356 if (layering_order_editor == 0) {
5357 layering_order_editor = new RegionLayeringOrderEditor (*this);
5358 layering_order_editor->set_position (WIN_POS_MOUSE);
5361 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5362 layering_order_editor->maybe_present ();
5366 Editor::update_region_layering_order_editor ()
5368 if (layering_order_editor && layering_order_editor->is_visible ()) {
5369 change_region_layering_order (true);
5374 Editor::setup_fade_images ()
5376 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5377 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5378 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5379 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5380 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5382 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5394 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5395 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5396 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5397 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5398 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5402 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5404 Editor::action_menu_item (std::string const & name)
5406 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5409 return *manage (a->create_menu_item ());
5413 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5415 EventBox* b = manage (new EventBox);
5416 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5417 Label* l = manage (new Label (name));
5421 _the_notebook.append_page (widget, *b);
5425 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5427 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5428 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5431 if (ev->type == GDK_2BUTTON_PRESS) {
5433 /* double-click on a notebook tab shrinks or expands the notebook */
5435 if (_notebook_shrunk) {
5436 if (pre_notebook_shrink_pane_width) {
5437 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5439 _notebook_shrunk = false;
5441 pre_notebook_shrink_pane_width = edit_pane.get_position();
5443 /* this expands the LHS of the edit pane to cover the notebook
5444 PAGE but leaves the tabs visible.
5446 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5447 _notebook_shrunk = true;
5455 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5457 using namespace Menu_Helpers;
5459 MenuList& items = _control_point_context_menu.items ();
5462 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5463 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5464 if (!can_remove_control_point (item)) {
5465 items.back().set_sensitive (false);
5468 _control_point_context_menu.popup (event->button.button, event->button.time);
5472 Editor::shift_key_released ()
5474 _stepping_axis_view = 0;