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());
1185 Editor::set_session (Session *t)
1187 SessionHandlePtr::set_session (t);
1193 zoom_range_clock->set_session (_session);
1194 _playlist_selector->set_session (_session);
1195 nudge_clock->set_session (_session);
1196 _summary->set_session (_session);
1197 _group_tabs->set_session (_session);
1198 _route_groups->set_session (_session);
1199 _regions->set_session (_session);
1200 _snapshots->set_session (_session);
1201 _routes->set_session (_session);
1202 _locations->set_session (_session);
1204 if (rhythm_ferret) {
1205 rhythm_ferret->set_session (_session);
1208 if (analysis_window) {
1209 analysis_window->set_session (_session);
1213 sfbrowser->set_session (_session);
1216 compute_fixed_ruler_scale ();
1218 /* Make sure we have auto loop and auto punch ranges */
1220 Location* loc = _session->locations()->auto_loop_location();
1222 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1224 if (loc->start() == loc->end()) {
1225 loc->set_end (loc->start() + 1);
1228 _session->locations()->add (loc, false);
1229 _session->set_auto_loop_location (loc);
1232 loc->set_name (_("Loop"));
1235 loc = _session->locations()->auto_punch_location();
1238 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1240 if (loc->start() == loc->end()) {
1241 loc->set_end (loc->start() + 1);
1244 _session->locations()->add (loc, false);
1245 _session->set_auto_punch_location (loc);
1248 loc->set_name (_("Punch"));
1251 refresh_location_display ();
1253 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1254 the selected Marker; this needs the LocationMarker list to be available.
1256 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1257 set_state (*node, Stateful::loading_state_version);
1259 /* catch up with the playhead */
1261 _session->request_locate (playhead_cursor->current_frame);
1262 _pending_initial_locate = true;
1266 /* These signals can all be emitted by a non-GUI thread. Therefore the
1267 handlers for them must not attempt to directly interact with the GUI,
1268 but use Gtkmm2ext::UI::instance()->call_slot();
1271 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1272 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1273 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1274 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1275 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1276 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1277 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1278 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1279 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1280 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1281 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1282 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1283 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1284 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1286 playhead_cursor->canvas_item.show ();
1288 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1289 Config->map_parameters (pc);
1290 _session->config.map_parameters (pc);
1292 restore_ruler_visibility ();
1293 //tempo_map_changed (PropertyChange (0));
1294 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1296 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1297 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1300 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1301 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1304 switch (_snap_type) {
1305 case SnapToRegionStart:
1306 case SnapToRegionEnd:
1307 case SnapToRegionSync:
1308 case SnapToRegionBoundary:
1309 build_region_boundary_cache ();
1316 /* register for undo history */
1317 _session->register_with_memento_command_factory(id(), this);
1319 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1321 start_updating_meters ();
1325 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1327 if (a->get_name() == "RegionMenu") {
1328 /* When the main menu's region menu is opened, we setup the actions so that they look right
1329 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1330 so we resensitize all region actions when the entered regionview or the region selection
1331 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1332 happens after the region context menu is opened. So we set a flag here, too.
1336 sensitize_the_right_region_actions ();
1337 _last_region_menu_was_main = true;
1342 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1344 using namespace Menu_Helpers;
1346 void (Editor::*emf)(FadeShape);
1347 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1350 images = &_xfade_in_images;
1351 emf = &Editor::set_fade_in_shape;
1353 images = &_xfade_out_images;
1354 emf = &Editor::set_fade_out_shape;
1359 _("Linear (for highly correlated material)"),
1360 *(*images)[FadeLinear],
1361 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1365 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1370 *(*images)[FadeConstantPower],
1371 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1374 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1379 *(*images)[FadeSymmetric],
1380 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1384 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1389 *(*images)[FadeSlow],
1390 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1393 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1398 *(*images)[FadeFast],
1399 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1402 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 /** Pop up a context menu for when the user clicks on a start crossfade */
1407 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1409 using namespace Menu_Helpers;
1411 MenuList& items (xfade_in_context_menu.items());
1413 if (items.empty()) {
1414 fill_xfade_menu (items, true);
1417 xfade_in_context_menu.popup (button, time);
1420 /** Pop up a context menu for when the user clicks on an end crossfade */
1422 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1424 using namespace Menu_Helpers;
1426 MenuList& items (xfade_out_context_menu.items());
1428 if (items.empty()) {
1429 fill_xfade_menu (items, false);
1432 xfade_out_context_menu.popup (button, time);
1436 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1438 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1440 using namespace Menu_Helpers;
1441 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1444 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1448 MenuList& items (fade_context_menu.items());
1451 switch (item_type) {
1453 case FadeInHandleItem:
1454 if (arv->audio_region()->fade_in_active()) {
1455 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1457 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1460 items.push_back (SeparatorElem());
1462 if (Profile->get_sae()) {
1464 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1465 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1472 *_fade_in_images[FadeLinear],
1473 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 *_fade_in_images[FadeSlow],
1483 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *_fade_in_images[FadeFast],
1492 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *_fade_in_images[FadeSymmetric],
1501 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1506 _("Constant Power"),
1507 *_fade_in_images[FadeConstantPower],
1508 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1511 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1517 case FadeOutHandleItem:
1518 if (arv->audio_region()->fade_out_active()) {
1519 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1521 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1524 items.push_back (SeparatorElem());
1526 if (Profile->get_sae()) {
1527 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1528 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1534 *_fade_out_images[FadeLinear],
1535 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1539 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1544 *_fade_out_images[FadeSlow],
1545 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1548 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1553 *_fade_out_images[FadeFast],
1554 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1557 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1562 *_fade_out_images[FadeSymmetric],
1563 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1568 _("Constant Power"),
1569 *_fade_out_images[FadeConstantPower],
1570 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1573 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1579 fatal << _("programming error: ")
1580 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1585 fade_context_menu.popup (button, time);
1589 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1591 using namespace Menu_Helpers;
1592 Menu* (Editor::*build_menu_function)();
1595 switch (item_type) {
1597 case RegionViewName:
1598 case RegionViewNameHighlight:
1599 case LeftFrameHandle:
1600 case RightFrameHandle:
1601 if (with_selection) {
1602 build_menu_function = &Editor::build_track_selection_context_menu;
1604 build_menu_function = &Editor::build_track_region_context_menu;
1609 if (with_selection) {
1610 build_menu_function = &Editor::build_track_selection_context_menu;
1612 build_menu_function = &Editor::build_track_context_menu;
1617 if (clicked_routeview->track()) {
1618 build_menu_function = &Editor::build_track_context_menu;
1620 build_menu_function = &Editor::build_track_bus_context_menu;
1625 /* probably shouldn't happen but if it does, we don't care */
1629 menu = (this->*build_menu_function)();
1630 menu->set_name ("ArdourContextMenu");
1632 /* now handle specific situations */
1634 switch (item_type) {
1636 case RegionViewName:
1637 case RegionViewNameHighlight:
1638 case LeftFrameHandle:
1639 case RightFrameHandle:
1640 if (!with_selection) {
1641 if (region_edit_menu_split_item) {
1642 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1643 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1645 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1648 if (region_edit_menu_split_multichannel_item) {
1649 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1650 region_edit_menu_split_multichannel_item->set_sensitive (true);
1652 region_edit_menu_split_multichannel_item->set_sensitive (false);
1665 /* probably shouldn't happen but if it does, we don't care */
1669 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1671 /* Bounce to disk */
1673 using namespace Menu_Helpers;
1674 MenuList& edit_items = menu->items();
1676 edit_items.push_back (SeparatorElem());
1678 switch (clicked_routeview->audio_track()->freeze_state()) {
1679 case AudioTrack::NoFreeze:
1680 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1683 case AudioTrack::Frozen:
1684 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1687 case AudioTrack::UnFrozen:
1688 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1694 if (item_type == StreamItem && clicked_routeview) {
1695 clicked_routeview->build_underlay_menu(menu);
1698 /* When the region menu is opened, we setup the actions so that they look right
1701 sensitize_the_right_region_actions ();
1702 _last_region_menu_was_main = false;
1704 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1705 menu->popup (button, time);
1709 Editor::build_track_context_menu ()
1711 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_context_menu.items();
1716 add_dstream_context_items (edit_items);
1717 return &track_context_menu;
1721 Editor::build_track_bus_context_menu ()
1723 using namespace Menu_Helpers;
1725 MenuList& edit_items = track_context_menu.items();
1728 add_bus_context_items (edit_items);
1729 return &track_context_menu;
1733 Editor::build_track_region_context_menu ()
1735 using namespace Menu_Helpers;
1736 MenuList& edit_items = track_region_context_menu.items();
1739 /* we've just cleared the track region context menu, so the menu that these
1740 two items were on will have disappeared; stop them dangling.
1742 region_edit_menu_split_item = 0;
1743 region_edit_menu_split_multichannel_item = 0;
1745 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1748 boost::shared_ptr<Track> tr;
1749 boost::shared_ptr<Playlist> pl;
1751 if ((tr = rtv->track())) {
1752 add_region_context_items (edit_items, tr);
1756 add_dstream_context_items (edit_items);
1758 return &track_region_context_menu;
1762 Editor::analyze_region_selection ()
1764 if (analysis_window == 0) {
1765 analysis_window = new AnalysisWindow();
1768 analysis_window->set_session(_session);
1770 analysis_window->show_all();
1773 analysis_window->set_regionmode();
1774 analysis_window->analyze();
1776 analysis_window->present();
1780 Editor::analyze_range_selection()
1782 if (analysis_window == 0) {
1783 analysis_window = new AnalysisWindow();
1786 analysis_window->set_session(_session);
1788 analysis_window->show_all();
1791 analysis_window->set_rangemode();
1792 analysis_window->analyze();
1794 analysis_window->present();
1798 Editor::build_track_selection_context_menu ()
1800 using namespace Menu_Helpers;
1801 MenuList& edit_items = track_selection_context_menu.items();
1802 edit_items.clear ();
1804 add_selection_context_items (edit_items);
1805 // edit_items.push_back (SeparatorElem());
1806 // add_dstream_context_items (edit_items);
1808 return &track_selection_context_menu;
1812 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1814 using namespace Menu_Helpers;
1816 /* OK, stick the region submenu at the top of the list, and then add
1820 RegionSelection rs = get_regions_from_selection_and_entered ();
1822 string::size_type pos = 0;
1823 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1825 /* we have to hack up the region name because "_" has a special
1826 meaning for menu titles.
1829 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1830 menu_item_name.replace (pos, 1, "__");
1834 if (_popup_region_menu_item == 0) {
1835 _popup_region_menu_item = new MenuItem (menu_item_name);
1836 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1837 _popup_region_menu_item->show ();
1839 _popup_region_menu_item->set_label (menu_item_name);
1842 const framepos_t position = get_preferred_edit_position (false, true);
1844 edit_items.push_back (*_popup_region_menu_item);
1845 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1846 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1848 edit_items.push_back (SeparatorElem());
1851 /** Add context menu items relevant to selection ranges.
1852 * @param edit_items List to add the items to.
1855 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1857 using namespace Menu_Helpers;
1859 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1860 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1865 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (
1869 _("Move Range Start to Previous Region Boundary"),
1870 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1874 edit_items.push_back (
1876 _("Move Range Start to Next Region Boundary"),
1877 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1881 edit_items.push_back (
1883 _("Move Range End to Previous Region Boundary"),
1884 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1888 edit_items.push_back (
1890 _("Move Range End to Next Region Boundary"),
1891 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1897 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1904 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1911 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1912 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1914 edit_items.push_back (SeparatorElem());
1915 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1916 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1917 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1918 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1919 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1924 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1930 Menu *play_menu = manage (new Menu);
1931 MenuList& play_items = play_menu->items();
1932 play_menu->set_name ("ArdourContextMenu");
1934 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1935 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1936 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1937 play_items.push_back (SeparatorElem());
1938 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1940 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1944 Menu *select_menu = manage (new Menu);
1945 MenuList& select_items = select_menu->items();
1946 select_menu->set_name ("ArdourContextMenu");
1948 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1951 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1954 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1957 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1958 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1959 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1960 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1961 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1962 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1964 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1968 Menu *cutnpaste_menu = manage (new Menu);
1969 MenuList& cutnpaste_items = cutnpaste_menu->items();
1970 cutnpaste_menu->set_name ("ArdourContextMenu");
1972 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1973 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1974 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1976 cutnpaste_items.push_back (SeparatorElem());
1978 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1979 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1981 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1983 /* Adding new material */
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1987 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1991 Menu *nudge_menu = manage (new Menu());
1992 MenuList& nudge_items = nudge_menu->items();
1993 nudge_menu->set_name ("ArdourContextMenu");
1995 edit_items.push_back (SeparatorElem());
1996 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2001 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2005 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2007 using namespace Menu_Helpers;
2011 Menu *play_menu = manage (new Menu);
2012 MenuList& play_items = play_menu->items();
2013 play_menu->set_name ("ArdourContextMenu");
2015 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2016 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2017 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2021 Menu *select_menu = manage (new Menu);
2022 MenuList& select_items = select_menu->items();
2023 select_menu->set_name ("ArdourContextMenu");
2025 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2027 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2028 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2029 select_items.push_back (SeparatorElem());
2030 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2031 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2032 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2039 Menu *cutnpaste_menu = manage (new Menu);
2040 MenuList& cutnpaste_items = cutnpaste_menu->items();
2041 cutnpaste_menu->set_name ("ArdourContextMenu");
2043 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2044 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2045 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2047 Menu *nudge_menu = manage (new Menu());
2048 MenuList& nudge_items = nudge_menu->items();
2049 nudge_menu->set_name ("ArdourContextMenu");
2051 edit_items.push_back (SeparatorElem());
2052 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2057 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2061 Editor::snap_type() const
2067 Editor::snap_mode() const
2073 Editor::set_snap_to (SnapType st)
2075 unsigned int snap_ind = (unsigned int)st;
2079 if (snap_ind > snap_type_strings.size() - 1) {
2081 _snap_type = (SnapType)snap_ind;
2084 string str = snap_type_strings[snap_ind];
2086 if (str != snap_type_selector.get_active_text()) {
2087 snap_type_selector.set_active_text (str);
2092 switch (_snap_type) {
2093 case SnapToBeatDiv128:
2094 case SnapToBeatDiv64:
2095 case SnapToBeatDiv32:
2096 case SnapToBeatDiv28:
2097 case SnapToBeatDiv24:
2098 case SnapToBeatDiv20:
2099 case SnapToBeatDiv16:
2100 case SnapToBeatDiv14:
2101 case SnapToBeatDiv12:
2102 case SnapToBeatDiv10:
2103 case SnapToBeatDiv8:
2104 case SnapToBeatDiv7:
2105 case SnapToBeatDiv6:
2106 case SnapToBeatDiv5:
2107 case SnapToBeatDiv4:
2108 case SnapToBeatDiv3:
2109 case SnapToBeatDiv2:
2110 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2111 update_tempo_based_rulers ();
2114 case SnapToRegionStart:
2115 case SnapToRegionEnd:
2116 case SnapToRegionSync:
2117 case SnapToRegionBoundary:
2118 build_region_boundary_cache ();
2126 SnapChanged (); /* EMIT SIGNAL */
2130 Editor::set_snap_mode (SnapMode mode)
2133 string str = snap_mode_strings[(int)mode];
2135 if (str != snap_mode_selector.get_active_text ()) {
2136 snap_mode_selector.set_active_text (str);
2142 Editor::set_edit_point_preference (EditPoint ep, bool force)
2144 bool changed = (_edit_point != ep);
2147 string str = edit_point_strings[(int)ep];
2149 if (str != edit_point_selector.get_active_text ()) {
2150 edit_point_selector.set_active_text (str);
2153 set_canvas_cursor ();
2155 if (!force && !changed) {
2159 const char* action=NULL;
2161 switch (_edit_point) {
2162 case EditAtPlayhead:
2163 action = "edit-at-playhead";
2165 case EditAtSelectedMarker:
2166 action = "edit-at-marker";
2169 action = "edit-at-mouse";
2173 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2175 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2179 bool in_track_canvas;
2181 if (!mouse_frame (foo, in_track_canvas)) {
2182 in_track_canvas = false;
2185 reset_canvas_action_sensitivity (in_track_canvas);
2191 Editor::set_state (const XMLNode& node, int /*version*/)
2193 const XMLProperty* prop;
2200 g.base_width = default_width;
2201 g.base_height = default_height;
2205 if ((geometry = find_named_node (node, "geometry")) != 0) {
2209 if ((prop = geometry->property("x_size")) == 0) {
2210 prop = geometry->property ("x-size");
2213 g.base_width = atoi(prop->value());
2215 if ((prop = geometry->property("y_size")) == 0) {
2216 prop = geometry->property ("y-size");
2219 g.base_height = atoi(prop->value());
2222 if ((prop = geometry->property ("x_pos")) == 0) {
2223 prop = geometry->property ("x-pos");
2226 x = atoi (prop->value());
2229 if ((prop = geometry->property ("y_pos")) == 0) {
2230 prop = geometry->property ("y-pos");
2233 y = atoi (prop->value());
2237 set_default_size (g.base_width, g.base_height);
2240 if (_session && (prop = node.property ("playhead"))) {
2242 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2243 playhead_cursor->set_position (pos);
2245 playhead_cursor->set_position (0);
2248 if ((prop = node.property ("mixer-width"))) {
2249 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2252 if ((prop = node.property ("zoom-focus"))) {
2253 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2256 if ((prop = node.property ("zoom"))) {
2257 reset_zoom (PBD::atof (prop->value()));
2259 reset_zoom (frames_per_unit);
2262 if ((prop = node.property ("snap-to"))) {
2263 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2266 if ((prop = node.property ("snap-mode"))) {
2267 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2270 if ((prop = node.property ("internal-snap-to"))) {
2271 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2274 if ((prop = node.property ("internal-snap-mode"))) {
2275 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2278 if ((prop = node.property ("pre-internal-snap-to"))) {
2279 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2282 if ((prop = node.property ("pre-internal-snap-mode"))) {
2283 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2286 if ((prop = node.property ("mouse-mode"))) {
2287 MouseMode m = str2mousemode(prop->value());
2288 set_mouse_mode (m, true);
2290 set_mouse_mode (MouseObject, true);
2293 if ((prop = node.property ("left-frame")) != 0) {
2295 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2299 reset_x_origin (pos);
2303 if ((prop = node.property ("y-origin")) != 0) {
2304 reset_y_origin (atof (prop->value ()));
2307 if ((prop = node.property ("internal-edit"))) {
2308 bool yn = string_is_affirmative (prop->value());
2309 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2311 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2312 tact->set_active (!yn);
2313 tact->set_active (yn);
2317 if ((prop = node.property ("join-object-range"))) {
2318 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2321 if ((prop = node.property ("edit-point"))) {
2322 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2325 if ((prop = node.property ("show-measures"))) {
2326 bool yn = string_is_affirmative (prop->value());
2327 _show_measures = yn;
2328 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2330 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2331 /* do it twice to force the change */
2332 tact->set_active (!yn);
2333 tact->set_active (yn);
2337 if ((prop = node.property ("follow-playhead"))) {
2338 bool yn = string_is_affirmative (prop->value());
2339 set_follow_playhead (yn);
2340 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2342 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2343 if (tact->get_active() != yn) {
2344 tact->set_active (yn);
2349 if ((prop = node.property ("stationary-playhead"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 set_stationary_playhead (yn);
2352 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2354 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2355 if (tact->get_active() != yn) {
2356 tact->set_active (yn);
2361 if ((prop = node.property ("region-list-sort-type"))) {
2362 RegionListSortType st;
2363 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2366 if ((prop = node.property ("show-editor-mixer"))) {
2368 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2371 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2372 bool yn = string_is_affirmative (prop->value());
2374 /* do it twice to force the change */
2376 tact->set_active (!yn);
2377 tact->set_active (yn);
2380 if ((prop = node.property ("show-editor-list"))) {
2382 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2385 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2386 bool yn = string_is_affirmative (prop->value());
2388 /* do it twice to force the change */
2390 tact->set_active (!yn);
2391 tact->set_active (yn);
2394 if ((prop = node.property (X_("editor-list-page")))) {
2395 _the_notebook.set_current_page (atoi (prop->value ()));
2398 if ((prop = node.property (X_("show-marker-lines")))) {
2399 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2401 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2402 bool yn = string_is_affirmative (prop->value ());
2404 tact->set_active (!yn);
2405 tact->set_active (yn);
2408 XMLNodeList children = node.children ();
2409 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2410 selection->set_state (**i, Stateful::current_state_version);
2411 _regions->set_state (**i);
2414 if ((prop = node.property ("maximised"))) {
2415 bool yn = string_is_affirmative (prop->value());
2417 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2421 if ((prop = node.property ("nudge-clock-value"))) {
2423 sscanf (prop->value().c_str(), "%" PRId64, &f);
2424 nudge_clock->set (f);
2426 nudge_clock->set_mode (AudioClock::Timecode);
2427 nudge_clock->set (_session->frame_rate() * 5, true);
2434 Editor::get_state ()
2436 XMLNode* node = new XMLNode ("Editor");
2439 id().print (buf, sizeof (buf));
2440 node->add_property ("id", buf);
2442 if (is_realized()) {
2443 Glib::RefPtr<Gdk::Window> win = get_window();
2445 int x, y, width, height;
2446 win->get_root_origin(x, y);
2447 win->get_size(width, height);
2449 XMLNode* geometry = new XMLNode ("geometry");
2451 snprintf(buf, sizeof(buf), "%d", width);
2452 geometry->add_property("x-size", string(buf));
2453 snprintf(buf, sizeof(buf), "%d", height);
2454 geometry->add_property("y-size", string(buf));
2455 snprintf(buf, sizeof(buf), "%d", x);
2456 geometry->add_property("x-pos", string(buf));
2457 snprintf(buf, sizeof(buf), "%d", y);
2458 geometry->add_property("y-pos", string(buf));
2459 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2460 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2461 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2462 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2463 geometry->add_property("edit-vertical-pane-pos", string(buf));
2465 node->add_child_nocopy (*geometry);
2468 maybe_add_mixer_strip_width (*node);
2470 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2471 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2472 node->add_property ("zoom", buf);
2473 node->add_property ("snap-to", enum_2_string (_snap_type));
2474 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2475 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2476 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2477 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2478 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2479 node->add_property ("edit-point", enum_2_string (_edit_point));
2481 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2482 node->add_property ("playhead", buf);
2483 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2484 node->add_property ("left-frame", buf);
2485 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2486 node->add_property ("y-origin", buf);
2488 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2489 node->add_property ("maximised", _maximised ? "yes" : "no");
2490 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2491 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2492 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2493 node->add_property ("mouse-mode", enum2str(mouse_mode));
2494 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2495 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2497 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2499 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2500 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2503 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2505 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2506 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2509 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2510 node->add_property (X_("editor-list-page"), buf);
2512 if (button_bindings) {
2513 XMLNode* bb = new XMLNode (X_("Buttons"));
2514 button_bindings->save (*bb);
2515 node->add_child_nocopy (*bb);
2518 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2520 node->add_child_nocopy (selection->get_state ());
2521 node->add_child_nocopy (_regions->get_state ());
2523 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2524 node->add_property ("nudge-clock-value", buf);
2531 /** @param y y offset from the top of all trackviews.
2532 * @return pair: TimeAxisView that y is over, layer index.
2533 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2534 * in stacked or expanded region display mode, otherwise 0.
2536 std::pair<TimeAxisView *, double>
2537 Editor::trackview_by_y_position (double y)
2539 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2541 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2547 return std::make_pair ( (TimeAxisView *) 0, 0);
2550 /** Snap a position to the grid, if appropriate, taking into account current
2551 * grid settings and also the state of any snap modifier keys that may be pressed.
2552 * @param start Position to snap.
2553 * @param event Event to get current key modifier information from, or 0.
2556 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2558 if (!_session || !event) {
2562 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2563 if (_snap_mode == SnapOff) {
2564 snap_to_internal (start, direction, for_mark);
2567 if (_snap_mode != SnapOff) {
2568 snap_to_internal (start, direction, for_mark);
2574 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2576 if (!_session || _snap_mode == SnapOff) {
2580 snap_to_internal (start, direction, for_mark);
2584 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2586 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2587 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2589 switch (_snap_type) {
2590 case SnapToTimecodeFrame:
2591 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2592 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2594 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2598 case SnapToTimecodeSeconds:
2599 if (_session->config.get_timecode_offset_negative()) {
2600 start += _session->config.get_timecode_offset ();
2602 start -= _session->config.get_timecode_offset ();
2604 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2605 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2607 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2610 if (_session->config.get_timecode_offset_negative()) {
2611 start -= _session->config.get_timecode_offset ();
2613 start += _session->config.get_timecode_offset ();
2617 case SnapToTimecodeMinutes:
2618 if (_session->config.get_timecode_offset_negative()) {
2619 start += _session->config.get_timecode_offset ();
2621 start -= _session->config.get_timecode_offset ();
2623 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2624 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2626 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2628 if (_session->config.get_timecode_offset_negative()) {
2629 start -= _session->config.get_timecode_offset ();
2631 start += _session->config.get_timecode_offset ();
2635 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2641 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2643 const framepos_t one_second = _session->frame_rate();
2644 const framepos_t one_minute = _session->frame_rate() * 60;
2645 framepos_t presnap = start;
2649 switch (_snap_type) {
2650 case SnapToTimecodeFrame:
2651 case SnapToTimecodeSeconds:
2652 case SnapToTimecodeMinutes:
2653 return timecode_snap_to_internal (start, direction, for_mark);
2656 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2657 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2659 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2664 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2665 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2667 start = (framepos_t) floor ((double) start / one_second) * one_second;
2672 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2673 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2675 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2680 start = _session->tempo_map().round_to_bar (start, direction);
2684 start = _session->tempo_map().round_to_beat (start, direction);
2687 case SnapToBeatDiv128:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2690 case SnapToBeatDiv64:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2693 case SnapToBeatDiv32:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2696 case SnapToBeatDiv28:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2699 case SnapToBeatDiv24:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2702 case SnapToBeatDiv20:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2705 case SnapToBeatDiv16:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2708 case SnapToBeatDiv14:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2711 case SnapToBeatDiv12:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2714 case SnapToBeatDiv10:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2717 case SnapToBeatDiv8:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2720 case SnapToBeatDiv7:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2723 case SnapToBeatDiv6:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2726 case SnapToBeatDiv5:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2729 case SnapToBeatDiv4:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2732 case SnapToBeatDiv3:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2735 case SnapToBeatDiv2:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2744 _session->locations()->marks_either_side (start, before, after);
2746 if (before == max_framepos && after == max_framepos) {
2747 /* No marks to snap to, so just don't snap */
2749 } else if (before == max_framepos) {
2751 } else if (after == max_framepos) {
2753 } else if (before != max_framepos && after != max_framepos) {
2754 /* have before and after */
2755 if ((start - before) < (after - start)) {
2764 case SnapToRegionStart:
2765 case SnapToRegionEnd:
2766 case SnapToRegionSync:
2767 case SnapToRegionBoundary:
2768 if (!region_boundary_cache.empty()) {
2770 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2771 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2773 if (direction > 0) {
2774 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2776 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2779 if (next != region_boundary_cache.begin ()) {
2784 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2785 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2787 if (start > (p + n) / 2) {
2796 switch (_snap_mode) {
2802 if (presnap > start) {
2803 if (presnap > (start + unit_to_frame(snap_threshold))) {
2807 } else if (presnap < start) {
2808 if (presnap < (start - unit_to_frame(snap_threshold))) {
2814 /* handled at entry */
2822 Editor::setup_toolbar ()
2824 HBox* mode_box = manage(new HBox);
2825 mode_box->set_border_width (2);
2826 mode_box->set_spacing(4);
2828 HBox* mouse_mode_box = manage (new HBox);
2829 HBox* mouse_mode_hbox1 = manage (new HBox);
2830 HBox* mouse_mode_hbox2 = manage (new HBox);
2831 VBox* mouse_mode_vbox1 = manage (new VBox);
2832 VBox* mouse_mode_vbox2 = manage (new VBox);
2833 Alignment* mouse_mode_align1 = manage (new Alignment);
2834 Alignment* mouse_mode_align2 = manage (new Alignment);
2836 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2837 mouse_mode_size_group->add_widget (mouse_move_button);
2838 mouse_mode_size_group->add_widget (mouse_select_button);
2839 mouse_mode_size_group->add_widget (mouse_zoom_button);
2840 mouse_mode_size_group->add_widget (mouse_gain_button);
2841 mouse_mode_size_group->add_widget (mouse_timefx_button);
2842 mouse_mode_size_group->add_widget (mouse_audition_button);
2843 mouse_mode_size_group->add_widget (mouse_draw_button);
2844 mouse_mode_size_group->add_widget (internal_edit_button);
2846 /* make them just a bit bigger */
2847 mouse_move_button.set_size_request (-1, 25);
2849 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2850 smart_mode_joiner->set_related_action (smart_mode_action);
2852 mouse_mode_hbox2->set_spacing (2);
2853 mouse_mode_box->set_spacing (2);
2855 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2856 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2857 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2858 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2859 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2860 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2861 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2863 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2864 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2866 mouse_mode_align1->add (*mouse_mode_vbox1);
2867 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2868 mouse_mode_align2->add (*mouse_mode_vbox2);
2869 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2871 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2872 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2874 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2875 if (!Profile->get_sae()) {
2876 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2878 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2880 edit_mode_selector.set_name ("EditModeSelector");
2881 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2882 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2884 mode_box->pack_start (edit_mode_selector, false, false);
2885 mode_box->pack_start (*mouse_mode_box, false, false);
2887 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2888 _mouse_mode_tearoff->set_name ("MouseModeBase");
2889 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2891 if (Profile->get_sae()) {
2892 _mouse_mode_tearoff->set_can_be_torn_off (false);
2895 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2896 &_mouse_mode_tearoff->tearoff_window()));
2897 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2898 &_mouse_mode_tearoff->tearoff_window(), 1));
2899 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2900 &_mouse_mode_tearoff->tearoff_window()));
2901 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window(), 1));
2906 _zoom_box.set_spacing (2);
2907 _zoom_box.set_border_width (2);
2911 zoom_in_button.set_name ("zoom button");
2912 zoom_in_button.set_image (::get_icon ("zoom_in"));
2913 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2915 zoom_in_button.set_related_action (act);
2917 zoom_out_button.set_name ("zoom button");
2918 zoom_out_button.set_image (::get_icon ("zoom_out"));
2919 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2920 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2921 zoom_out_button.set_related_action (act);
2923 zoom_out_full_button.set_name ("zoom button");
2924 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2925 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2926 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2927 zoom_out_full_button.set_related_action (act);
2929 zoom_focus_selector.set_name ("ZoomFocusSelector");
2930 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2931 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2933 _zoom_box.pack_start (zoom_out_button, false, false);
2934 _zoom_box.pack_start (zoom_in_button, false, false);
2935 _zoom_box.pack_start (zoom_out_full_button, false, false);
2937 _zoom_box.pack_start (zoom_focus_selector, false, false);
2939 /* Track zoom buttons */
2940 tav_expand_button.set_name ("TrackHeightButton");
2941 tav_expand_button.set_size_request (-1, 20);
2942 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2943 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2944 act->connect_proxy (tav_expand_button);
2946 tav_shrink_button.set_name ("TrackHeightButton");
2947 tav_shrink_button.set_size_request (-1, 20);
2948 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2949 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2950 act->connect_proxy (tav_shrink_button);
2952 _zoom_box.pack_start (tav_shrink_button);
2953 _zoom_box.pack_start (tav_expand_button);
2955 _zoom_tearoff = manage (new TearOff (_zoom_box));
2957 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window()));
2959 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window(), 0));
2961 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window()));
2963 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window(), 0));
2966 snap_box.set_spacing (1);
2967 snap_box.set_border_width (2);
2969 snap_type_selector.set_name ("SnapTypeSelector");
2970 set_popdown_strings (snap_type_selector, snap_type_strings);
2971 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2973 snap_mode_selector.set_name ("SnapModeSelector");
2974 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2975 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2977 edit_point_selector.set_name ("EditPointSelector");
2978 set_popdown_strings (edit_point_selector, edit_point_strings);
2979 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2981 snap_box.pack_start (snap_mode_selector, false, false);
2982 snap_box.pack_start (snap_type_selector, false, false);
2983 snap_box.pack_start (edit_point_selector, false, false);
2987 HBox *nudge_box = manage (new HBox);
2988 nudge_box->set_spacing (2);
2989 nudge_box->set_border_width (2);
2991 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2992 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2994 nudge_box->pack_start (nudge_backward_button, false, false);
2995 nudge_box->pack_start (nudge_forward_button, false, false);
2996 nudge_box->pack_start (*nudge_clock, false, false);
2999 /* Pack everything in... */
3001 HBox* hbox = manage (new HBox);
3002 hbox->set_spacing(10);
3004 _tools_tearoff = manage (new TearOff (*hbox));
3005 _tools_tearoff->set_name ("MouseModeBase");
3006 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3008 if (Profile->get_sae()) {
3009 _tools_tearoff->set_can_be_torn_off (false);
3012 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013 &_tools_tearoff->tearoff_window()));
3014 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015 &_tools_tearoff->tearoff_window(), 0));
3016 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017 &_tools_tearoff->tearoff_window()));
3018 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window(), 0));
3021 toolbar_hbox.set_spacing (10);
3022 toolbar_hbox.set_border_width (1);
3024 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3025 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3026 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3028 hbox->pack_start (snap_box, false, false);
3029 if (!Profile->get_small_screen()) {
3030 hbox->pack_start (*nudge_box, false, false);
3032 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3034 hbox->pack_start (panic_box, false, false);
3038 toolbar_base.set_name ("ToolBarBase");
3039 toolbar_base.add (toolbar_hbox);
3041 _toolbar_viewport.add (toolbar_base);
3042 /* stick to the required height but allow width to vary if there's not enough room */
3043 _toolbar_viewport.set_size_request (1, -1);
3045 toolbar_frame.set_shadow_type (SHADOW_OUT);
3046 toolbar_frame.set_name ("BaseFrame");
3047 toolbar_frame.add (_toolbar_viewport);
3051 Editor::setup_tooltips ()
3053 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3054 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3055 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3056 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3057 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3058 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3059 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3060 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3061 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3062 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3063 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3064 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3065 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3066 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3067 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3068 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3069 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3070 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3071 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3072 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3073 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3074 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3075 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3079 Editor::convert_drop_to_paths (
3080 vector<string>& paths,
3081 const RefPtr<Gdk::DragContext>& /*context*/,
3084 const SelectionData& data,
3088 if (_session == 0) {
3092 vector<string> uris = data.get_uris();
3096 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3097 are actually URI lists. So do it by hand.
3100 if (data.get_target() != "text/plain") {
3104 /* Parse the "uri-list" format that Nautilus provides,
3105 where each pathname is delimited by \r\n.
3107 THERE MAY BE NO NULL TERMINATING CHAR!!!
3110 string txt = data.get_text();
3114 p = (const char *) malloc (txt.length() + 1);
3115 txt.copy (const_cast<char *> (p), txt.length(), 0);
3116 const_cast<char*>(p)[txt.length()] = '\0';
3122 while (g_ascii_isspace (*p))
3126 while (*q && (*q != '\n') && (*q != '\r')) {
3133 while (q > p && g_ascii_isspace (*q))
3138 uris.push_back (string (p, q - p + 1));
3142 p = strchr (p, '\n');
3154 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3156 if ((*i).substr (0,7) == "file://") {
3158 string const p = PBD::url_decode (*i);
3160 // scan forward past three slashes
3162 string::size_type slashcnt = 0;
3163 string::size_type n = 0;
3164 string::const_iterator x = p.begin();
3166 while (slashcnt < 3 && x != p.end()) {
3169 } else if (slashcnt == 3) {
3176 if (slashcnt != 3 || x == p.end()) {
3177 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3181 paths.push_back (p.substr (n - 1));
3189 Editor::new_tempo_section ()
3195 Editor::map_transport_state ()
3197 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3199 if (_session && _session->transport_stopped()) {
3200 have_pending_keyboard_selection = false;
3203 update_loop_range_view (true);
3209 Editor::begin_reversible_command (string name)
3212 _session->begin_reversible_command (name);
3217 Editor::begin_reversible_command (GQuark q)
3220 _session->begin_reversible_command (q);
3225 Editor::commit_reversible_command ()
3228 _session->commit_reversible_command ();
3233 Editor::history_changed ()
3237 if (undo_action && _session) {
3238 if (_session->undo_depth() == 0) {
3239 label = S_("Command|Undo");
3241 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3243 undo_action->property_label() = label;
3246 if (redo_action && _session) {
3247 if (_session->redo_depth() == 0) {
3250 label = string_compose(_("Redo (%1)"), _session->next_redo());
3252 redo_action->property_label() = label;
3257 Editor::duplicate_range (bool with_dialog)
3261 if (mouse_mode == MouseRange) {
3262 if (selection->time.length() == 0) {
3267 RegionSelection rs = get_regions_from_selection_and_entered ();
3269 if (mouse_mode != MouseRange && rs.empty()) {
3275 ArdourDialog win (_("Duplicate"));
3276 Label label (_("Number of duplications:"));
3277 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3278 SpinButton spinner (adjustment, 0.0, 1);
3281 win.get_vbox()->set_spacing (12);
3282 win.get_vbox()->pack_start (hbox);
3283 hbox.set_border_width (6);
3284 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3286 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3287 place, visually. so do this by hand.
3290 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3291 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3292 spinner.grab_focus();
3298 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3299 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3300 win.set_default_response (RESPONSE_ACCEPT);
3302 win.set_position (WIN_POS_MOUSE);
3304 spinner.grab_focus ();
3306 switch (win.run ()) {
3307 case RESPONSE_ACCEPT:
3313 times = adjustment.get_value();
3316 if (mouse_mode == MouseRange) {
3317 duplicate_selection (times);
3319 duplicate_some_regions (rs, times);
3324 Editor::set_edit_mode (EditMode m)
3326 Config->set_edit_mode (m);
3330 Editor::cycle_edit_mode ()
3332 switch (Config->get_edit_mode()) {
3334 if (Profile->get_sae()) {
3335 Config->set_edit_mode (Lock);
3337 Config->set_edit_mode (Splice);
3341 Config->set_edit_mode (Lock);
3344 Config->set_edit_mode (Slide);
3350 Editor::edit_mode_selection_done ()
3352 string s = edit_mode_selector.get_active_text ();
3355 Config->set_edit_mode (string_to_edit_mode (s));
3360 Editor::snap_type_selection_done ()
3362 string choice = snap_type_selector.get_active_text();
3363 SnapType snaptype = SnapToBeat;
3365 if (choice == _("Beats/2")) {
3366 snaptype = SnapToBeatDiv2;
3367 } else if (choice == _("Beats/3")) {
3368 snaptype = SnapToBeatDiv3;
3369 } else if (choice == _("Beats/4")) {
3370 snaptype = SnapToBeatDiv4;
3371 } else if (choice == _("Beats/5")) {
3372 snaptype = SnapToBeatDiv5;
3373 } else if (choice == _("Beats/6")) {
3374 snaptype = SnapToBeatDiv6;
3375 } else if (choice == _("Beats/7")) {
3376 snaptype = SnapToBeatDiv7;
3377 } else if (choice == _("Beats/8")) {
3378 snaptype = SnapToBeatDiv8;
3379 } else if (choice == _("Beats/10")) {
3380 snaptype = SnapToBeatDiv10;
3381 } else if (choice == _("Beats/12")) {
3382 snaptype = SnapToBeatDiv12;
3383 } else if (choice == _("Beats/14")) {
3384 snaptype = SnapToBeatDiv14;
3385 } else if (choice == _("Beats/16")) {
3386 snaptype = SnapToBeatDiv16;
3387 } else if (choice == _("Beats/20")) {
3388 snaptype = SnapToBeatDiv20;
3389 } else if (choice == _("Beats/24")) {
3390 snaptype = SnapToBeatDiv24;
3391 } else if (choice == _("Beats/28")) {
3392 snaptype = SnapToBeatDiv28;
3393 } else if (choice == _("Beats/32")) {
3394 snaptype = SnapToBeatDiv32;
3395 } else if (choice == _("Beats/64")) {
3396 snaptype = SnapToBeatDiv64;
3397 } else if (choice == _("Beats/128")) {
3398 snaptype = SnapToBeatDiv128;
3399 } else if (choice == _("Beats")) {
3400 snaptype = SnapToBeat;
3401 } else if (choice == _("Bars")) {
3402 snaptype = SnapToBar;
3403 } else if (choice == _("Marks")) {
3404 snaptype = SnapToMark;
3405 } else if (choice == _("Region starts")) {
3406 snaptype = SnapToRegionStart;
3407 } else if (choice == _("Region ends")) {
3408 snaptype = SnapToRegionEnd;
3409 } else if (choice == _("Region bounds")) {
3410 snaptype = SnapToRegionBoundary;
3411 } else if (choice == _("Region syncs")) {
3412 snaptype = SnapToRegionSync;
3413 } else if (choice == _("CD Frames")) {
3414 snaptype = SnapToCDFrame;
3415 } else if (choice == _("Timecode Frames")) {
3416 snaptype = SnapToTimecodeFrame;
3417 } else if (choice == _("Timecode Seconds")) {
3418 snaptype = SnapToTimecodeSeconds;
3419 } else if (choice == _("Timecode Minutes")) {
3420 snaptype = SnapToTimecodeMinutes;
3421 } else if (choice == _("Seconds")) {
3422 snaptype = SnapToSeconds;
3423 } else if (choice == _("Minutes")) {
3424 snaptype = SnapToMinutes;
3427 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3429 ract->set_active ();
3434 Editor::snap_mode_selection_done ()
3436 string choice = snap_mode_selector.get_active_text();
3437 SnapMode mode = SnapNormal;
3439 if (choice == _("No Grid")) {
3441 } else if (choice == _("Grid")) {
3443 } else if (choice == _("Magnetic")) {
3444 mode = SnapMagnetic;
3447 RefPtr<RadioAction> ract = snap_mode_action (mode);
3450 ract->set_active (true);
3455 Editor::cycle_edit_point (bool with_marker)
3457 switch (_edit_point) {
3459 set_edit_point_preference (EditAtPlayhead);
3461 case EditAtPlayhead:
3463 set_edit_point_preference (EditAtSelectedMarker);
3465 set_edit_point_preference (EditAtMouse);
3468 case EditAtSelectedMarker:
3469 set_edit_point_preference (EditAtMouse);
3475 Editor::edit_point_selection_done ()
3477 string choice = edit_point_selector.get_active_text();
3478 EditPoint ep = EditAtSelectedMarker;
3480 if (choice == _("Marker")) {
3481 set_edit_point_preference (EditAtSelectedMarker);
3482 } else if (choice == _("Playhead")) {
3483 set_edit_point_preference (EditAtPlayhead);
3485 set_edit_point_preference (EditAtMouse);
3488 RefPtr<RadioAction> ract = edit_point_action (ep);
3491 ract->set_active (true);
3496 Editor::zoom_focus_selection_done ()
3498 string choice = zoom_focus_selector.get_active_text();
3499 ZoomFocus focus_type = ZoomFocusLeft;
3501 if (choice == _("Left")) {
3502 focus_type = ZoomFocusLeft;
3503 } else if (choice == _("Right")) {
3504 focus_type = ZoomFocusRight;
3505 } else if (choice == _("Center")) {
3506 focus_type = ZoomFocusCenter;
3507 } else if (choice == _("Playhead")) {
3508 focus_type = ZoomFocusPlayhead;
3509 } else if (choice == _("Mouse")) {
3510 focus_type = ZoomFocusMouse;
3511 } else if (choice == _("Edit point")) {
3512 focus_type = ZoomFocusEdit;
3515 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3518 ract->set_active ();
3523 Editor::edit_controls_button_release (GdkEventButton* ev)
3525 if (Keyboard::is_context_menu_event (ev)) {
3526 ARDOUR_UI::instance()->add_route (this);
3527 } else if (ev->button == 1) {
3528 selection->clear_tracks ();
3535 Editor::mouse_select_button_release (GdkEventButton* ev)
3537 /* this handles just right-clicks */
3539 if (ev->button != 3) {
3547 Editor::set_zoom_focus (ZoomFocus f)
3549 string str = zoom_focus_strings[(int)f];
3551 if (str != zoom_focus_selector.get_active_text()) {
3552 zoom_focus_selector.set_active_text (str);
3555 if (zoom_focus != f) {
3562 Editor::ensure_float (Window& win)
3564 win.set_transient_for (*this);
3568 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3570 /* recover or initialize pane positions. do this here rather than earlier because
3571 we don't want the positions to change the child allocations, which they seem to do.
3577 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3586 XMLNode* geometry = find_named_node (*node, "geometry");
3588 if (which == static_cast<Paned*> (&edit_pane)) {
3590 if (done & Horizontal) {
3594 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3595 _notebook_shrunk = string_is_affirmative (prop->value ());
3598 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3599 /* initial allocation is 90% to canvas, 10% to notebook */
3600 pos = (int) floor (alloc.get_width() * 0.90f);
3601 snprintf (buf, sizeof(buf), "%d", pos);
3603 pos = atoi (prop->value());
3606 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3607 edit_pane.set_position (pos);
3610 done = (Pane) (done | Horizontal);
3612 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3614 if (done & Vertical) {
3618 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3619 /* initial allocation is 90% to canvas, 10% to summary */
3620 pos = (int) floor (alloc.get_height() * 0.90f);
3621 snprintf (buf, sizeof(buf), "%d", pos);
3624 pos = atoi (prop->value());
3627 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3628 editor_summary_pane.set_position (pos);
3631 done = (Pane) (done | Vertical);
3636 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3638 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3639 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3640 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3641 top_hbox.remove (toolbar_frame);
3646 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3648 if (toolbar_frame.get_parent() == 0) {
3649 top_hbox.pack_end (toolbar_frame);
3654 Editor::set_show_measures (bool yn)
3656 if (_show_measures != yn) {
3659 if ((_show_measures = yn) == true) {
3661 tempo_lines->show();
3669 Editor::toggle_follow_playhead ()
3671 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3673 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3674 set_follow_playhead (tact->get_active());
3678 /** @param yn true to follow playhead, otherwise false.
3679 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3682 Editor::set_follow_playhead (bool yn, bool catch_up)
3684 if (_follow_playhead != yn) {
3685 if ((_follow_playhead = yn) == true && catch_up) {
3687 reset_x_origin_to_follow_playhead ();
3694 Editor::toggle_stationary_playhead ()
3696 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3698 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3699 set_stationary_playhead (tact->get_active());
3704 Editor::set_stationary_playhead (bool yn)
3706 if (_stationary_playhead != yn) {
3707 if ((_stationary_playhead = yn) == true) {
3709 // FIXME need a 3.0 equivalent of this 2.X call
3710 // update_current_screen ();
3717 Editor::playlist_selector () const
3719 return *_playlist_selector;
3723 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3727 switch (_snap_type) {
3732 case SnapToBeatDiv128:
3735 case SnapToBeatDiv64:
3738 case SnapToBeatDiv32:
3741 case SnapToBeatDiv28:
3744 case SnapToBeatDiv24:
3747 case SnapToBeatDiv20:
3750 case SnapToBeatDiv16:
3753 case SnapToBeatDiv14:
3756 case SnapToBeatDiv12:
3759 case SnapToBeatDiv10:
3762 case SnapToBeatDiv8:
3765 case SnapToBeatDiv7:
3768 case SnapToBeatDiv6:
3771 case SnapToBeatDiv5:
3774 case SnapToBeatDiv4:
3777 case SnapToBeatDiv3:
3780 case SnapToBeatDiv2:
3786 return _session->tempo_map().meter_at (position).divisions_per_bar();
3791 case SnapToTimecodeFrame:
3792 case SnapToTimecodeSeconds:
3793 case SnapToTimecodeMinutes:
3796 case SnapToRegionStart:
3797 case SnapToRegionEnd:
3798 case SnapToRegionSync:
3799 case SnapToRegionBoundary:
3809 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3813 ret = nudge_clock->current_duration (pos);
3814 next = ret + 1; /* XXXX fix me */
3820 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3822 ArdourDialog dialog (_("Playlist Deletion"));
3823 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3824 "If it is kept, its audio files will not be cleaned.\n"
3825 "If it is deleted, audio files used by it alone will be cleaned."),
3828 dialog.set_position (WIN_POS_CENTER);
3829 dialog.get_vbox()->pack_start (label);
3833 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3834 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3835 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3837 switch (dialog.run ()) {
3838 case RESPONSE_ACCEPT:
3839 /* delete the playlist */
3843 case RESPONSE_REJECT:
3844 /* keep the playlist */
3856 Editor::audio_region_selection_covers (framepos_t where)
3858 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3859 if ((*a)->region()->covers (where)) {
3868 Editor::prepare_for_cleanup ()
3870 cut_buffer->clear_regions ();
3871 cut_buffer->clear_playlists ();
3873 selection->clear_regions ();
3874 selection->clear_playlists ();
3876 _regions->suspend_redisplay ();
3880 Editor::finish_cleanup ()
3882 _regions->resume_redisplay ();
3886 Editor::transport_loop_location()
3889 return _session->locations()->auto_loop_location();
3896 Editor::transport_punch_location()
3899 return _session->locations()->auto_punch_location();
3906 Editor::control_layout_scroll (GdkEventScroll* ev)
3908 if (Keyboard::some_magic_widget_has_focus()) {
3912 switch (ev->direction) {
3914 scroll_tracks_up_line ();
3918 case GDK_SCROLL_DOWN:
3919 scroll_tracks_down_line ();
3923 /* no left/right handling yet */
3931 Editor::session_state_saved (string)
3934 _snapshots->redisplay ();
3938 Editor::update_tearoff_visibility()
3940 bool visible = Config->get_keep_tearoffs();
3941 _mouse_mode_tearoff->set_visible (visible);
3942 _tools_tearoff->set_visible (visible);
3943 _zoom_tearoff->set_visible (visible);
3947 Editor::maximise_editing_space ()
3959 Editor::restore_editing_space ()
3971 * Make new playlists for a given track and also any others that belong
3972 * to the same active route group with the `edit' property.
3977 Editor::new_playlists (TimeAxisView* v)
3979 begin_reversible_command (_("new playlists"));
3980 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3981 _session->playlists->get (playlists);
3982 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3983 commit_reversible_command ();
3987 * Use a copy of the current playlist for a given track and also any others that belong
3988 * to the same active route group with the `edit' property.
3993 Editor::copy_playlists (TimeAxisView* v)
3995 begin_reversible_command (_("copy playlists"));
3996 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3997 _session->playlists->get (playlists);
3998 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3999 commit_reversible_command ();
4002 /** Clear the current playlist for a given track and also any others that belong
4003 * to the same active route group with the `edit' property.
4008 Editor::clear_playlists (TimeAxisView* v)
4010 begin_reversible_command (_("clear playlists"));
4011 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4012 _session->playlists->get (playlists);
4013 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4014 commit_reversible_command ();
4018 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4020 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4024 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4026 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4030 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4032 atv.clear_playlist ();
4036 Editor::on_key_press_event (GdkEventKey* ev)
4038 return key_press_focus_accelerator_handler (*this, ev);
4042 Editor::on_key_release_event (GdkEventKey* ev)
4044 return Gtk::Window::on_key_release_event (ev);
4045 // return key_press_focus_accelerator_handler (*this, ev);
4048 /** Queue up a change to the viewport x origin.
4049 * @param frame New x origin.
4052 Editor::reset_x_origin (framepos_t frame)
4054 pending_visual_change.add (VisualChange::TimeOrigin);
4055 pending_visual_change.time_origin = frame;
4056 ensure_visual_change_idle_handler ();
4060 Editor::reset_y_origin (double y)
4062 pending_visual_change.add (VisualChange::YOrigin);
4063 pending_visual_change.y_origin = y;
4064 ensure_visual_change_idle_handler ();
4068 Editor::reset_zoom (double fpu)
4070 clamp_frames_per_unit (fpu);
4072 if (fpu == frames_per_unit) {
4076 pending_visual_change.add (VisualChange::ZoomLevel);
4077 pending_visual_change.frames_per_unit = fpu;
4078 ensure_visual_change_idle_handler ();
4082 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4084 reset_x_origin (frame);
4087 if (!no_save_visual) {
4088 undo_visual_stack.push_back (current_visual_state(false));
4092 Editor::VisualState::VisualState (bool with_tracks)
4093 : gui_state (with_tracks ? new GUIObjectState : 0)
4097 Editor::VisualState::~VisualState ()
4102 Editor::VisualState*
4103 Editor::current_visual_state (bool with_tracks)
4105 VisualState* vs = new VisualState (with_tracks);
4106 vs->y_position = vertical_adjustment.get_value();
4107 vs->frames_per_unit = frames_per_unit;
4108 vs->leftmost_frame = leftmost_frame;
4109 vs->zoom_focus = zoom_focus;
4112 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4119 Editor::undo_visual_state ()
4121 if (undo_visual_stack.empty()) {
4125 VisualState* vs = undo_visual_stack.back();
4126 undo_visual_stack.pop_back();
4129 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4131 use_visual_state (*vs);
4135 Editor::redo_visual_state ()
4137 if (redo_visual_stack.empty()) {
4141 VisualState* vs = redo_visual_stack.back();
4142 redo_visual_stack.pop_back();
4144 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4146 use_visual_state (*vs);
4150 Editor::swap_visual_state ()
4152 if (undo_visual_stack.empty()) {
4153 redo_visual_state ();
4155 undo_visual_state ();
4160 Editor::use_visual_state (VisualState& vs)
4162 PBD::Unwinder<bool> nsv (no_save_visual, true);
4164 _routes->suspend_redisplay ();
4166 vertical_adjustment.set_value (vs.y_position);
4168 set_zoom_focus (vs.zoom_focus);
4169 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4172 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4174 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4175 (*i)->reset_visual_state ();
4179 _routes->update_visibility ();
4180 _routes->resume_redisplay ();
4183 /** This is the core function that controls the zoom level of the canvas. It is called
4184 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4185 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4188 Editor::set_frames_per_unit (double fpu)
4191 tempo_lines->tempo_map_changed();
4194 frames_per_unit = fpu;
4196 /* convert fpu to frame count */
4198 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4200 if (frames_per_unit != zoom_range_clock->current_duration()) {
4201 zoom_range_clock->set (frames);
4204 bool const showing_time_selection =
4205 mouse_mode == MouseRange ||
4206 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4208 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4209 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4210 (*i)->reshow_selection (selection->time);
4214 ZoomChanged (); /* EMIT_SIGNAL */
4216 //reset_scrolling_region ();
4218 if (playhead_cursor) {
4219 playhead_cursor->set_position (playhead_cursor->current_frame);
4222 refresh_location_display();
4223 _summary->set_overlays_dirty ();
4225 update_marker_labels ();
4231 Editor::ensure_visual_change_idle_handler ()
4233 if (pending_visual_change.idle_handler_id < 0) {
4234 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4239 Editor::_idle_visual_changer (void* arg)
4241 return static_cast<Editor*>(arg)->idle_visual_changer ();
4245 Editor::idle_visual_changer ()
4247 /* set_horizontal_position() below (and maybe other calls) call
4248 gtk_main_iteration(), so it's possible that a signal will be handled
4249 half-way through this method. If this signal wants an
4250 idle_visual_changer we must schedule another one after this one, so
4251 mark the idle_handler_id as -1 here to allow that. Also make a note
4252 that we are doing the visual change, so that changes in response to
4253 super-rapid-screen-update can be dropped if we are still processing
4256 pending_visual_change.idle_handler_id = -1;
4257 pending_visual_change.being_handled = true;
4259 VisualChange::Type p = pending_visual_change.pending;
4260 pending_visual_change.pending = (VisualChange::Type) 0;
4262 double const last_time_origin = horizontal_position ();
4264 if (p & VisualChange::ZoomLevel) {
4265 set_frames_per_unit (pending_visual_change.frames_per_unit);
4267 compute_fixed_ruler_scale ();
4268 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4269 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4270 update_tempo_based_rulers ();
4272 if (p & VisualChange::TimeOrigin) {
4273 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4275 if (p & VisualChange::YOrigin) {
4276 vertical_adjustment.set_value (pending_visual_change.y_origin);
4279 if (last_time_origin == horizontal_position ()) {
4280 /* changed signal not emitted */
4281 update_fixed_rulers ();
4282 redisplay_tempo (true);
4285 _summary->set_overlays_dirty ();
4287 pending_visual_change.being_handled = false;
4288 return 0; /* this is always a one-shot call */
4291 struct EditorOrderTimeAxisSorter {
4292 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4293 return a->order () < b->order ();
4298 Editor::sort_track_selection (TrackViewList& sel)
4300 EditorOrderTimeAxisSorter cmp;
4305 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4308 framepos_t where = 0;
4309 EditPoint ep = _edit_point;
4311 if (from_context_menu && (ep == EditAtMouse)) {
4312 return event_frame (&context_click_event, 0, 0);
4315 if (entered_marker) {
4316 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4317 return entered_marker->position();
4320 if (ignore_playhead && ep == EditAtPlayhead) {
4321 ep = EditAtSelectedMarker;
4325 case EditAtPlayhead:
4326 where = _session->audible_frame();
4327 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4330 case EditAtSelectedMarker:
4331 if (!selection->markers.empty()) {
4333 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4336 where = loc->start();
4340 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4348 if (!mouse_frame (where, ignored)) {
4349 /* XXX not right but what can we do ? */
4353 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4361 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4363 if (!_session) return;
4365 begin_reversible_command (cmd);
4369 if ((tll = transport_loop_location()) == 0) {
4370 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4371 XMLNode &before = _session->locations()->get_state();
4372 _session->locations()->add (loc, true);
4373 _session->set_auto_loop_location (loc);
4374 XMLNode &after = _session->locations()->get_state();
4375 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4377 XMLNode &before = tll->get_state();
4378 tll->set_hidden (false, this);
4379 tll->set (start, end);
4380 XMLNode &after = tll->get_state();
4381 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4384 commit_reversible_command ();
4388 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4390 if (!_session) return;
4392 begin_reversible_command (cmd);
4396 if ((tpl = transport_punch_location()) == 0) {
4397 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4398 XMLNode &before = _session->locations()->get_state();
4399 _session->locations()->add (loc, true);
4400 _session->set_auto_loop_location (loc);
4401 XMLNode &after = _session->locations()->get_state();
4402 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4405 XMLNode &before = tpl->get_state();
4406 tpl->set_hidden (false, this);
4407 tpl->set (start, end);
4408 XMLNode &after = tpl->get_state();
4409 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4412 commit_reversible_command ();
4415 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4416 * @param rs List to which found regions are added.
4417 * @param where Time to look at.
4418 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4421 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4423 const TrackViewList* tracks;
4426 tracks = &track_views;
4431 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4433 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4436 boost::shared_ptr<Track> tr;
4437 boost::shared_ptr<Playlist> pl;
4439 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4441 boost::shared_ptr<RegionList> regions = pl->regions_at (
4442 (framepos_t) floor ( (double) where * tr->speed()));
4444 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4445 RegionView* rv = rtv->view()->find_view (*i);
4456 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4458 const TrackViewList* tracks;
4461 tracks = &track_views;
4466 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4467 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4469 boost::shared_ptr<Track> tr;
4470 boost::shared_ptr<Playlist> pl;
4472 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4474 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4475 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4477 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4479 RegionView* rv = rtv->view()->find_view (*i);
4490 /** Start with regions that are selected. Then add equivalent regions
4491 * on tracks in the same active edit-enabled route group as any of
4492 * the regions that we started with.
4496 Editor::get_regions_from_selection ()
4498 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4501 /** Get regions using the following method:
4503 * Make an initial region list using the selected regions, unless
4504 * the edit point is `mouse' and the mouse is over an unselected
4505 * region. In this case, start with just that region.
4507 * Then, add equivalent regions in active edit groups to the region list.
4509 * Then, search the list of selected tracks to find any selected tracks which
4510 * do not contain regions already in the region list. If there are no selected
4511 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4512 * than just the selected.
4514 * Add any regions that are under the edit point on these tracks to get the
4515 * returned region list.
4517 * The rationale here is that the mouse edit point is special in that
4518 * its position describes both a time and a track; the other edit
4519 * modes only describe a time. Hence if the edit point is `mouse' we
4520 * ignore selected tracks, as we assume the user means something by
4521 * pointing at a particular track. Also in this case we take note of
4522 * the region directly under the edit point, as there is always just one
4523 * (rather than possibly several with non-mouse edit points).
4527 Editor::get_regions_from_selection_and_edit_point ()
4529 RegionSelection regions;
4531 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4532 regions.add (entered_regionview);
4534 regions = selection->regions;
4537 TrackViewList tracks;
4539 if (_edit_point != EditAtMouse) {
4540 tracks = selection->tracks;
4543 /* Add any other regions that are in the same
4544 edit-activated route group as one of our regions.
4546 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4547 framepos_t const where = get_preferred_edit_position ();
4549 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4550 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4551 * is enabled, so consider all tracks
4553 tracks = track_views;
4556 if (!tracks.empty()) {
4557 /* now search the selected tracks for tracks which don't
4558 already contain regions to be acted upon, and get regions at
4559 the edit point on those tracks too.
4561 TrackViewList tracks_without_relevant_regions;
4563 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4564 if (!regions.involves (**t)) {
4565 /* there are no equivalent regions on this track */
4566 tracks_without_relevant_regions.push_back (*t);
4570 if (!tracks_without_relevant_regions.empty()) {
4571 /* there are some selected tracks with neither selected
4572 * regions or their equivalents: act upon all regions in
4575 get_regions_at (regions, where, tracks_without_relevant_regions);
4582 /** Start with regions that are selected, or the entered regionview if none are selected.
4583 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4584 * of the regions that we started with.
4588 Editor::get_regions_from_selection_and_entered ()
4590 RegionSelection regions = selection->regions;
4592 if (regions.empty() && entered_regionview) {
4593 regions.add (entered_regionview);
4596 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4600 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4602 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4604 RouteTimeAxisView* tatv;
4606 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4608 boost::shared_ptr<Playlist> pl;
4609 vector<boost::shared_ptr<Region> > results;
4611 boost::shared_ptr<Track> tr;
4613 if ((tr = tatv->track()) == 0) {
4618 if ((pl = (tr->playlist())) != 0) {
4619 pl->get_region_list_equivalent_regions (region, results);
4622 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4623 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4624 regions.push_back (marv);
4633 Editor::show_rhythm_ferret ()
4635 if (rhythm_ferret == 0) {
4636 rhythm_ferret = new RhythmFerret(*this);
4639 rhythm_ferret->set_session (_session);
4640 rhythm_ferret->show ();
4641 rhythm_ferret->present ();
4645 Editor::first_idle ()
4647 MessageDialog* dialog = 0;
4649 if (track_views.size() > 1) {
4650 dialog = new MessageDialog (
4652 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4656 ARDOUR_UI::instance()->flush_pending ();
4659 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4663 // first idle adds route children (automation tracks), so we need to redisplay here
4664 _routes->redisplay ();
4671 Editor::_idle_resize (gpointer arg)
4673 return ((Editor*)arg)->idle_resize ();
4677 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4679 if (resize_idle_id < 0) {
4680 resize_idle_id = g_idle_add (_idle_resize, this);
4681 _pending_resize_amount = 0;
4684 /* make a note of the smallest resulting height, so that we can clamp the
4685 lower limit at TimeAxisView::hSmall */
4687 int32_t min_resulting = INT32_MAX;
4689 _pending_resize_amount += h;
4690 _pending_resize_view = view;
4692 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4694 if (selection->tracks.contains (_pending_resize_view)) {
4695 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4696 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4700 if (min_resulting < 0) {
4705 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4706 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4710 /** Handle pending resizing of tracks */
4712 Editor::idle_resize ()
4714 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4716 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4717 selection->tracks.contains (_pending_resize_view)) {
4719 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4720 if (*i != _pending_resize_view) {
4721 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4726 _pending_resize_amount = 0;
4728 _group_tabs->set_dirty ();
4729 resize_idle_id = -1;
4737 ENSURE_GUI_THREAD (*this, &Editor::located);
4739 playhead_cursor->set_position (_session->audible_frame ());
4740 if (_follow_playhead && !_pending_initial_locate) {
4741 reset_x_origin_to_follow_playhead ();
4744 _pending_locate_request = false;
4745 _pending_initial_locate = false;
4749 Editor::region_view_added (RegionView *)
4751 _summary->set_dirty ();
4755 Editor::region_view_removed ()
4757 _summary->set_dirty ();
4761 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4763 TrackViewList::const_iterator j = track_views.begin ();
4764 while (j != track_views.end()) {
4765 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4766 if (rtv && rtv->route() == r) {
4777 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4781 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4782 TimeAxisView* tv = axis_view_from_route (*i);
4792 Editor::add_routes (RouteList& routes)
4794 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4796 RouteTimeAxisView *rtv;
4797 list<RouteTimeAxisView*> new_views;
4799 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4800 boost::shared_ptr<Route> route = (*x);
4802 if (route->is_hidden() || route->is_monitor()) {
4806 DataType dt = route->input()->default_type();
4808 if (dt == ARDOUR::DataType::AUDIO) {
4809 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4810 rtv->set_route (route);
4811 } else if (dt == ARDOUR::DataType::MIDI) {
4812 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4813 rtv->set_route (route);
4815 throw unknown_type();
4818 new_views.push_back (rtv);
4819 track_views.push_back (rtv);
4821 rtv->effective_gain_display ();
4823 if (internal_editing()) {
4824 rtv->enter_internal_edit_mode ();
4826 rtv->leave_internal_edit_mode ();
4829 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4830 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4833 _routes->routes_added (new_views);
4834 _summary->routes_added (new_views);
4836 if (show_editor_mixer_when_tracks_arrive) {
4837 show_editor_mixer (true);
4840 editor_list_button.set_sensitive (true);
4844 Editor::timeaxisview_deleted (TimeAxisView *tv)
4846 if (_session && _session->deletion_in_progress()) {
4847 /* the situation is under control */
4851 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4853 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4855 _routes->route_removed (tv);
4857 if (tv == entered_track) {
4861 TimeAxisView::Children c = tv->get_child_list ();
4862 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4863 if (entered_track == i->get()) {
4868 /* remove it from the list of track views */
4870 TrackViewList::iterator i;
4872 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4873 i = track_views.erase (i);
4876 /* update whatever the current mixer strip is displaying, if revelant */
4878 boost::shared_ptr<Route> route;
4881 route = rtav->route ();
4884 if (current_mixer_strip && current_mixer_strip->route() == route) {
4886 TimeAxisView* next_tv;
4888 if (track_views.empty()) {
4890 } else if (i == track_views.end()) {
4891 next_tv = track_views.front();
4898 set_selected_mixer_strip (*next_tv);
4900 /* make the editor mixer strip go away setting the
4901 * button to inactive (which also unticks the menu option)
4904 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4910 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4912 if (apply_to_selection) {
4913 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4915 TrackSelection::iterator j = i;
4918 hide_track_in_display (*i, false);
4923 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4925 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4926 // this will hide the mixer strip
4927 set_selected_mixer_strip (*tv);
4930 _routes->hide_track_in_display (*tv);
4935 Editor::sync_track_view_list_and_routes ()
4937 track_views = TrackViewList (_routes->views ());
4939 _summary->set_dirty ();
4940 _group_tabs->set_dirty ();
4942 return false; // do not call again (until needed)
4946 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4948 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4953 /** Find a RouteTimeAxisView by the ID of its route */
4955 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4957 RouteTimeAxisView* v;
4959 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4960 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4961 if(v->route()->id() == id) {
4971 Editor::fit_route_group (RouteGroup *g)
4973 TrackViewList ts = axis_views_from_routes (g->route_list ());
4978 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4980 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4983 _session->cancel_audition ();
4987 if (_session->is_auditioning()) {
4988 _session->cancel_audition ();
4989 if (r == last_audition_region) {
4994 _session->audition_region (r);
4995 last_audition_region = r;
5000 Editor::hide_a_region (boost::shared_ptr<Region> r)
5002 r->set_hidden (true);
5006 Editor::show_a_region (boost::shared_ptr<Region> r)
5008 r->set_hidden (false);
5012 Editor::audition_region_from_region_list ()
5014 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5018 Editor::hide_region_from_region_list ()
5020 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5024 Editor::show_region_in_region_list ()
5026 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5030 Editor::step_edit_status_change (bool yn)
5033 start_step_editing ();
5035 stop_step_editing ();
5040 Editor::start_step_editing ()
5042 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5046 Editor::stop_step_editing ()
5048 step_edit_connection.disconnect ();
5052 Editor::check_step_edit ()
5054 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5055 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5057 mtv->check_step_edit ();
5061 return true; // do it again, till we stop
5065 Editor::scroll_press (Direction dir)
5067 ++_scroll_callbacks;
5069 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5070 /* delay the first auto-repeat */
5076 scroll_backward (1);
5084 scroll_tracks_up_line ();
5088 scroll_tracks_down_line ();
5092 /* do hacky auto-repeat */
5093 if (!_scroll_connection.connected ()) {
5095 _scroll_connection = Glib::signal_timeout().connect (
5096 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5099 _scroll_callbacks = 0;
5106 Editor::scroll_release ()
5108 _scroll_connection.disconnect ();
5111 /** Queue a change for the Editor viewport x origin to follow the playhead */
5113 Editor::reset_x_origin_to_follow_playhead ()
5115 framepos_t const frame = playhead_cursor->current_frame;
5117 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5119 if (_session->transport_speed() < 0) {
5121 if (frame > (current_page_frames() / 2)) {
5122 center_screen (frame-(current_page_frames()/2));
5124 center_screen (current_page_frames()/2);
5131 if (frame < leftmost_frame) {
5133 if (_session->transport_rolling()) {
5134 /* rolling; end up with the playhead at the right of the page */
5135 l = frame - current_page_frames ();
5137 /* not rolling: end up with the playhead 1/4 of the way along the page */
5138 l = frame - current_page_frames() / 4;
5142 if (_session->transport_rolling()) {
5143 /* rolling: end up with the playhead on the left of the page */
5146 /* not rolling: end up with the playhead 3/4 of the way along the page */
5147 l = frame - 3 * current_page_frames() / 4;
5155 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5161 Editor::super_rapid_screen_update ()
5163 if (!_session || !_session->engine().running()) {
5167 /* METERING / MIXER STRIPS */
5169 /* update track meters, if required */
5170 if (is_mapped() && meters_running) {
5171 RouteTimeAxisView* rtv;
5172 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5173 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5174 rtv->fast_update ();
5179 /* and any current mixer strip */
5180 if (current_mixer_strip) {
5181 current_mixer_strip->fast_update ();
5184 /* PLAYHEAD AND VIEWPORT */
5186 framepos_t const frame = _session->audible_frame();
5188 /* There are a few reasons why we might not update the playhead / viewport stuff:
5190 * 1. we don't update things when there's a pending locate request, otherwise
5191 * when the editor requests a locate there is a chance that this method
5192 * will move the playhead before the locate request is processed, causing
5194 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5195 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5198 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5200 last_update_frame = frame;
5202 if (!_dragging_playhead) {
5203 playhead_cursor->set_position (frame);
5206 if (!_stationary_playhead) {
5208 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5209 /* We only do this if we aren't already
5210 handling a visual change (ie if
5211 pending_visual_change.being_handled is
5212 false) so that these requests don't stack
5213 up there are too many of them to handle in
5216 reset_x_origin_to_follow_playhead ();
5221 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5225 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5226 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5227 if (target <= 0.0) {
5230 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5231 target = (target * 0.15) + (current * 0.85);
5237 set_horizontal_position (current);
5246 Editor::session_going_away ()
5248 _have_idled = false;
5250 _session_connections.drop_connections ();
5252 super_rapid_screen_update_connection.disconnect ();
5254 selection->clear ();
5255 cut_buffer->clear ();
5257 clicked_regionview = 0;
5258 clicked_axisview = 0;
5259 clicked_routeview = 0;
5260 entered_regionview = 0;
5262 last_update_frame = 0;
5265 playhead_cursor->canvas_item.hide ();
5267 /* rip everything out of the list displays */
5271 _route_groups->clear ();
5273 /* do this first so that deleting a track doesn't reset cms to null
5274 and thus cause a leak.
5277 if (current_mixer_strip) {
5278 if (current_mixer_strip->get_parent() != 0) {
5279 global_hpacker.remove (*current_mixer_strip);
5281 delete current_mixer_strip;
5282 current_mixer_strip = 0;
5285 /* delete all trackviews */
5287 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5290 track_views.clear ();
5292 zoom_range_clock->set_session (0);
5293 nudge_clock->set_session (0);
5295 editor_list_button.set_active(false);
5296 editor_list_button.set_sensitive(false);
5298 /* clear tempo/meter rulers */
5299 remove_metric_marks ();
5301 clear_marker_display ();
5303 current_bbt_points_begin = current_bbt_points_end;
5305 /* get rid of any existing editor mixer strip */
5307 WindowTitle title(Glib::get_application_name());
5308 title += _("Editor");
5310 set_title (title.get_string());
5312 SessionHandlePtr::session_going_away ();
5317 Editor::show_editor_list (bool yn)
5320 _the_notebook.show ();
5322 _the_notebook.hide ();
5327 Editor::change_region_layering_order (bool from_context_menu)
5329 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5331 if (!clicked_routeview) {
5332 if (layering_order_editor) {
5333 layering_order_editor->hide ();
5338 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5344 boost::shared_ptr<Playlist> pl = track->playlist();
5350 if (layering_order_editor == 0) {
5351 layering_order_editor = new RegionLayeringOrderEditor (*this);
5352 layering_order_editor->set_position (WIN_POS_MOUSE);
5355 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5356 layering_order_editor->maybe_present ();
5360 Editor::update_region_layering_order_editor ()
5362 if (layering_order_editor && layering_order_editor->is_visible ()) {
5363 change_region_layering_order (true);
5368 Editor::setup_fade_images ()
5370 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5371 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5372 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5373 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5374 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5376 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5377 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5378 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5379 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5380 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5382 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5396 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5398 Editor::action_menu_item (std::string const & name)
5400 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5403 return *manage (a->create_menu_item ());
5407 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5409 EventBox* b = manage (new EventBox);
5410 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5411 Label* l = manage (new Label (name));
5415 _the_notebook.append_page (widget, *b);
5419 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5421 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5422 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5425 if (ev->type == GDK_2BUTTON_PRESS) {
5427 /* double-click on a notebook tab shrinks or expands the notebook */
5429 if (_notebook_shrunk) {
5430 if (pre_notebook_shrink_pane_width) {
5431 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5433 _notebook_shrunk = false;
5435 pre_notebook_shrink_pane_width = edit_pane.get_position();
5437 /* this expands the LHS of the edit pane to cover the notebook
5438 PAGE but leaves the tabs visible.
5440 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5441 _notebook_shrunk = true;
5449 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5451 using namespace Menu_Helpers;
5453 MenuList& items = _control_point_context_menu.items ();
5456 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5457 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5458 if (!can_remove_control_point (item)) {
5459 items.back().set_sensitive (false);
5462 _control_point_context_menu.popup (event->button.button, event->button.time);
5466 Editor::shift_key_released ()
5468 _stepping_axis_view = 0;