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"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include <gtkmm2ext/grouped_buttons.h>
53 #include <gtkmm2ext/gtk_ui.h>
54 #include <gtkmm2ext/tearoff.h>
55 #include <gtkmm2ext/utils.h>
56 #include <gtkmm2ext/window_title.h>
57 #include <gtkmm2ext/choice.h>
58 #include <gtkmm2ext/cell_renderer_pixbuf_toggle.h>
60 #include "ardour/audio_diskstream.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
77 #include "control_protocol/control_protocol.h"
82 #include "playlist_selector.h"
83 #include "audio_region_view.h"
84 #include "rgb_macros.h"
85 #include "selection.h"
86 #include "audio_streamview.h"
87 #include "time_axis_view.h"
88 #include "audio_time_axis.h"
90 #include "crossfade_view.h"
91 #include "canvas-noevent-text.h"
93 #include "public_editor.h"
94 #include "crossfade_edit.h"
95 #include "canvas_impl.h"
98 #include "gui_thread.h"
99 #include "simpleline.h"
100 #include "rhythm_ferret.h"
102 #include "tempo_lines.h"
103 #include "analysis_window.h"
104 #include "bundle_manager.h"
105 #include "global_port_matrix.h"
106 #include "editor_drag.h"
107 #include "editor_group_tabs.h"
108 #include "automation_time_axis.h"
109 #include "editor_routes.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "editor_route_groups.h"
113 #include "editor_regions.h"
114 #include "editor_locations.h"
115 #include "editor_snapshots.h"
116 #include "editor_summary.h"
117 #include "region_layering_order_editor.h"
118 #include "mouse_cursors.h"
119 #include "editor_cursors.h"
124 #include "imageframe_socket_handler.h"
128 using namespace ARDOUR;
131 using namespace Glib;
132 using namespace Gtkmm2ext;
133 using namespace Editing;
135 using PBD::internationalize;
137 using Gtkmm2ext::Keyboard;
139 const double Editor::timebar_height = 15.0;
141 static const gchar *_snap_type_strings[] = {
143 N_("Timecode Frames"),
144 N_("Timecode Seconds"),
145 N_("Timecode Minutes"),
173 static const gchar *_snap_mode_strings[] = {
180 static const gchar *_edit_point_strings[] = {
187 static const gchar *_zoom_focus_strings[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 show_me_the_size (Requisition* r, const char* what)
213 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,
221 it is no longer accessible. so stop that. this doesn't happen on X11,
222 just the quartz backend.
227 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
229 gint pos = pane->get_position ();
231 if (pos > max_width_of_lhs) {
232 pane->set_position (max_width_of_lhs);
238 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
240 /* time display buttons */
241 , minsec_label (_("Mins:Secs"))
242 , bbt_label (_("Bars:Beats"))
243 , timecode_label (_("Timecode"))
244 , frame_label (_("Samples"))
245 , tempo_label (_("Tempo"))
246 , meter_label (_("Meter"))
247 , mark_label (_("Location Markers"))
248 , range_mark_label (_("Range Markers"))
249 , transport_mark_label (_("Loop/Punch Ranges"))
250 , cd_mark_label (_("CD Markers"))
251 , edit_packer (4, 4, true)
253 /* the values here don't matter: layout widgets
254 reset them as needed.
257 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
259 /* tool bar related */
261 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
266 , global_automation_button (_("automation"))
268 , midi_panic_button (_("Panic"))
271 , image_socket_listener(0)
276 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
286 /* we are a singleton */
288 PublicEditor::_instance = this;
292 selection = new Selection (this);
293 cut_buffer = new Selection (this);
295 clicked_regionview = 0;
296 clicked_axisview = 0;
297 clicked_routeview = 0;
298 clicked_crossfadeview = 0;
299 clicked_control_point = 0;
300 last_update_frame = 0;
301 pre_press_cursor = 0;
302 _drags = new DragManager (this);
303 current_mixer_strip = 0;
304 current_bbt_points = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 snap_threshold = 5.0;
317 bbt_beat_subdivision = 4;
320 last_autoscroll_x = 0;
321 last_autoscroll_y = 0;
322 autoscroll_active = false;
323 autoscroll_timeout_tag = -1;
328 current_interthread_info = 0;
329 _show_measures = true;
330 show_gain_after_trim = false;
331 verbose_cursor_on = true;
332 last_item_entered = 0;
334 have_pending_keyboard_selection = false;
335 _follow_playhead = true;
336 _stationary_playhead = false;
337 _xfade_visibility = true;
338 editor_ruler_menu = 0;
339 no_ruler_shown_update = false;
341 session_range_marker_menu = 0;
342 range_marker_menu = 0;
343 marker_menu_item = 0;
344 tempo_or_meter_marker_menu = 0;
345 transport_marker_menu = 0;
346 new_transport_marker_menu = 0;
347 editor_mixer_strip_width = Wide;
348 show_editor_mixer_when_tracks_arrive = false;
349 region_edit_menu_split_multichannel_item = 0;
350 region_edit_menu_split_item = 0;
353 current_stepping_trackview = 0;
355 entered_regionview = 0;
357 clear_entered_track = false;
360 button_release_can_deselect = true;
361 _dragging_playhead = false;
362 _dragging_edit_point = false;
363 select_new_marker = false;
365 layering_order_editor = 0;
367 no_save_visual = false;
370 scrubbing_direction = 0;
374 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
375 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
376 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
377 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
378 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
380 _edit_point = EditAtMouse;
381 _internal_editing = false;
382 current_canvas_cursor = 0;
384 frames_per_unit = 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks = 0;
388 zoom_focus = ZoomFocusLeft;
389 set_zoom_focus (ZoomFocusLeft);
390 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
392 bbt_label.set_name ("EditorTimeButton");
393 bbt_label.set_size_request (-1, (int)timebar_height);
394 bbt_label.set_alignment (1.0, 0.5);
395 bbt_label.set_padding (5,0);
397 bbt_label.set_no_show_all();
398 minsec_label.set_name ("EditorTimeButton");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 minsec_label.hide ();
403 minsec_label.set_no_show_all();
404 timecode_label.set_name ("EditorTimeButton");
405 timecode_label.set_size_request (-1, (int)timebar_height);
406 timecode_label.set_alignment (1.0, 0.5);
407 timecode_label.set_padding (5,0);
408 timecode_label.hide ();
409 timecode_label.set_no_show_all();
410 frame_label.set_name ("EditorTimeButton");
411 frame_label.set_size_request (-1, (int)timebar_height);
412 frame_label.set_alignment (1.0, 0.5);
413 frame_label.set_padding (5,0);
415 frame_label.set_no_show_all();
417 tempo_label.set_name ("EditorTimeButton");
418 tempo_label.set_size_request (-1, (int)timebar_height);
419 tempo_label.set_alignment (1.0, 0.5);
420 tempo_label.set_padding (5,0);
422 tempo_label.set_no_show_all();
423 meter_label.set_name ("EditorTimeButton");
424 meter_label.set_size_request (-1, (int)timebar_height);
425 meter_label.set_alignment (1.0, 0.5);
426 meter_label.set_padding (5,0);
428 meter_label.set_no_show_all();
429 mark_label.set_name ("EditorTimeButton");
430 mark_label.set_size_request (-1, (int)timebar_height);
431 mark_label.set_alignment (1.0, 0.5);
432 mark_label.set_padding (5,0);
434 mark_label.set_no_show_all();
435 cd_mark_label.set_name ("EditorTimeButton");
436 cd_mark_label.set_size_request (-1, (int)timebar_height);
437 cd_mark_label.set_alignment (1.0, 0.5);
438 cd_mark_label.set_padding (5,0);
439 cd_mark_label.hide();
440 cd_mark_label.set_no_show_all();
441 range_mark_label.set_name ("EditorTimeButton");
442 range_mark_label.set_size_request (-1, (int)timebar_height);
443 range_mark_label.set_alignment (1.0, 0.5);
444 range_mark_label.set_padding (5,0);
445 range_mark_label.hide();
446 range_mark_label.set_no_show_all();
447 transport_mark_label.set_name ("EditorTimeButton");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
451 transport_mark_label.hide();
452 transport_mark_label.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
456 _summary = new EditorSummary (this);
458 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
459 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
460 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
461 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
462 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
464 edit_controls_vbox.set_spacing (0);
465 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
466 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
468 HBox* h = manage (new HBox);
469 _group_tabs = new EditorGroupTabs (this);
470 h->pack_start (*_group_tabs, PACK_SHRINK);
471 h->pack_start (edit_controls_vbox);
472 controls_layout.add (*h);
474 controls_layout.set_name ("EditControlsBase");
475 controls_layout.add_events (Gdk::SCROLL_MASK);
476 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
478 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
479 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
480 controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request));
482 _cursors = new MouseCursors;
484 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
485 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
486 0.0, 1.0, 100.0, 1.0));
487 pad_line_1->property_color_rgba() = 0xFF0000FF;
491 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
492 time_canvas_vbox.set_size_request (-1, -1);
494 ruler_label_event_box.add (ruler_label_vbox);
495 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
496 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
498 time_button_event_box.add (time_button_vbox);
499 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
500 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
502 /* these enable us to have a dedicated window (for cursor setting, etc.)
503 for the canvas areas.
506 track_canvas_event_box.add (*track_canvas);
508 time_canvas_event_box.add (time_canvas_vbox);
509 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
511 edit_packer.set_col_spacings (0);
512 edit_packer.set_row_spacings (0);
513 edit_packer.set_homogeneous (false);
514 edit_packer.set_border_width (0);
515 edit_packer.set_name ("EditorWindow");
517 /* labels for the rulers */
518 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
519 /* labels for the marker "tracks" */
520 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
522 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
524 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
526 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
528 bottom_hbox.set_border_width (2);
529 bottom_hbox.set_spacing (3);
531 _route_groups = new EditorRouteGroups (this);
532 _routes = new EditorRoutes (this);
533 _regions = new EditorRegions (this);
534 _snapshots = new EditorSnapshots (this);
535 _locations = new EditorLocations (this);
539 nlabel = manage (new Label (_("Regions")));
540 nlabel->set_angle (-90);
541 the_notebook.append_page (_regions->widget (), *nlabel);
542 nlabel = manage (new Label (_("Tracks & Busses")));
543 nlabel->set_angle (-90);
544 the_notebook.append_page (_routes->widget (), *nlabel);
545 nlabel = manage (new Label (_("Snapshots")));
546 nlabel->set_angle (-90);
547 the_notebook.append_page (_snapshots->widget (), *nlabel);
548 nlabel = manage (new Label (_("Route Groups")));
549 nlabel->set_angle (-90);
550 the_notebook.append_page (_route_groups->widget (), *nlabel);
551 nlabel = manage (new Label (_("Ranges & Marks")));
552 nlabel->set_angle (-90);
553 the_notebook.append_page (_locations->widget (), *nlabel);
555 the_notebook.set_show_tabs (true);
556 the_notebook.set_scrollable (true);
557 the_notebook.popup_disable ();
558 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
559 the_notebook.show_all ();
561 post_maximal_editor_width = 0;
562 post_maximal_horizontal_pane_position = 0;
563 post_maximal_editor_height = 0;
564 post_maximal_vertical_pane_position = 0;
566 editor_summary_pane.pack1(edit_packer);
568 Button* summary_arrows_left_left = manage (new Button);
569 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
571 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
572 Button* summary_arrows_left_right = manage (new Button);
573 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
574 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
575 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
576 VBox* summary_arrows_left = manage (new VBox);
577 summary_arrows_left->pack_start (*summary_arrows_left_left);
578 summary_arrows_left->pack_start (*summary_arrows_left_right);
580 Button* summary_arrows_right_left = manage (new Button);
581 summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
582 summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
583 summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
584 Button* summary_arrows_right_right = manage (new Button);
585 summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
586 summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
587 summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
588 VBox* summary_arrows_right = manage (new VBox);
589 summary_arrows_right->pack_start (*summary_arrows_right_left);
590 summary_arrows_right->pack_start (*summary_arrows_right_right);
592 Frame* summary_frame = manage (new Frame);
593 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 special OS X treatment 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, false, true);
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 */
638 setup_midi_toolbar ();
640 _snap_type = SnapToBeat;
641 set_snap_to (_snap_type);
642 _snap_mode = SnapOff;
643 set_snap_mode (_snap_mode);
644 set_mouse_mode (MouseObject, true);
645 set_edit_point_preference (EditAtMouse, true);
647 _playlist_selector = new PlaylistSelector();
648 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
650 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
654 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
655 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
657 nudge_forward_button.set_name ("TransportButton");
658 nudge_backward_button.set_name ("TransportButton");
660 fade_context_menu.set_name ("ArdourContextMenu");
662 /* icons, titles, WM stuff */
664 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
665 Glib::RefPtr<Gdk::Pixbuf> icon;
667 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
668 window_icons.push_back (icon);
670 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
671 window_icons.push_back (icon);
673 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
677 window_icons.push_back (icon);
679 if (!window_icons.empty()) {
680 set_icon_list (window_icons);
681 set_default_icon_list (window_icons);
684 WindowTitle title(Glib::get_application_name());
685 title += _("Editor");
686 set_title (title.get_string());
687 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
690 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
692 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
693 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
695 /* allow external control surfaces/protocols to do various things */
697 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
698 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
699 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
700 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
701 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
703 /* problematic: has to return a value and thus cannot be x-thread */
705 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
707 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
709 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
711 _ignore_region_action = false;
712 _last_region_menu_was_main = false;
713 _popup_region_menu_item = 0;
715 _show_marker_lines = false;
716 _over_region_trim_target = false;
721 setup_fade_images ();
727 if(image_socket_listener) {
728 if(image_socket_listener->is_connected())
730 image_socket_listener->close_connection() ;
733 delete image_socket_listener ;
734 image_socket_listener = 0 ;
739 delete _route_groups;
745 Editor::add_toplevel_controls (Container& cont)
747 vpacker.pack_start (cont, false, false);
752 Editor::catch_vanishing_regionview (RegionView *rv)
754 /* note: the selection will take care of the vanishing
755 audioregionview by itself.
758 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
762 if (clicked_regionview == rv) {
763 clicked_regionview = 0;
766 if (entered_regionview == rv) {
767 set_entered_regionview (0);
770 if (!_all_region_actions_sensitized) {
771 sensitize_all_region_actions (true);
776 Editor::set_entered_regionview (RegionView* rv)
778 if (rv == entered_regionview) {
782 if (entered_regionview) {
783 entered_regionview->exited ();
786 if ((entered_regionview = rv) != 0) {
787 entered_regionview->entered (internal_editing ());
790 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
791 /* This RegionView entry might have changed what region actions
792 are allowed, so sensitize them all in case a key is pressed.
794 sensitize_all_region_actions (true);
799 Editor::set_entered_track (TimeAxisView* tav)
802 entered_track->exited ();
805 if ((entered_track = tav) != 0) {
806 entered_track->entered ();
811 Editor::show_window ()
813 if (! is_visible ()) {
816 /* re-hide editor list if necessary */
817 editor_list_button_toggled ();
819 /* re-hide summary widget if necessary */
820 parameter_changed ("show-summary");
822 parameter_changed ("show-edit-group-tabs");
824 /* now reset all audio_time_axis heights, because widgets might need
830 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
831 tv = (static_cast<TimeAxisView*>(*i));
840 Editor::instant_save ()
842 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
847 _session->add_instant_xml(get_state());
849 Config->add_instant_xml(get_state());
854 Editor::zoom_adjustment_changed ()
860 double fpu = zoom_range_clock.current_duration() / _canvas_width;
864 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
865 } else if (fpu > _session->current_end_frame() / _canvas_width) {
866 fpu = _session->current_end_frame() / _canvas_width;
867 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
874 Editor::control_scroll (float fraction)
876 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
882 double step = fraction * current_page_frames();
885 _control_scroll_target is an optional<T>
887 it acts like a pointer to an framepos_t, with
888 a operator conversion to boolean to check
889 that it has a value could possibly use
890 playhead_cursor->current_frame to store the
891 value and a boolean in the class to know
892 when it's out of date
895 if (!_control_scroll_target) {
896 _control_scroll_target = _session->transport_frame();
897 _dragging_playhead = true;
900 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
901 *_control_scroll_target = 0;
902 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
903 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
905 *_control_scroll_target += (framepos_t) floor (step);
908 /* move visuals, we'll catch up with it later */
910 playhead_cursor->set_position (*_control_scroll_target);
911 UpdateAllTransportClocks (*_control_scroll_target);
913 if (*_control_scroll_target > (current_page_frames() / 2)) {
914 /* try to center PH in window */
915 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
921 Now we do a timeout to actually bring the session to the right place
922 according to the playhead. This is to avoid reading disk buffers on every
923 call to control_scroll, which is driven by ScrollTimeline and therefore
924 probably by a control surface wheel which can generate lots of events.
926 /* cancel the existing timeout */
928 control_scroll_connection.disconnect ();
930 /* add the next timeout */
932 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
936 Editor::deferred_control_scroll (framepos_t /*target*/)
938 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
939 // reset for next stream
940 _control_scroll_target = boost::none;
941 _dragging_playhead = false;
946 Editor::access_action (std::string action_group, std::string action_item)
952 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
955 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
963 Editor::on_realize ()
965 Window::on_realize ();
970 Editor::map_position_change (framepos_t frame)
972 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
978 if (_follow_playhead) {
979 center_screen (frame);
982 playhead_cursor->set_position (frame);
986 Editor::center_screen (framepos_t frame)
988 double page = _canvas_width * frames_per_unit;
990 /* if we're off the page, then scroll.
993 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
994 center_screen_internal (frame, page);
999 Editor::center_screen_internal (framepos_t frame, float page)
1004 frame -= (framepos_t) page;
1009 reset_x_origin (frame);
1014 Editor::update_title ()
1016 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1019 bool dirty = _session->dirty();
1021 string session_name;
1023 if (_session->snap_name() != _session->name()) {
1024 session_name = _session->snap_name();
1026 session_name = _session->name();
1030 session_name = "*" + session_name;
1033 WindowTitle title(session_name);
1034 title += Glib::get_application_name();
1035 set_title (title.get_string());
1040 Editor::set_session (Session *t)
1042 SessionHandlePtr::set_session (t);
1048 zoom_range_clock.set_session (_session);
1049 _playlist_selector->set_session (_session);
1050 nudge_clock.set_session (_session);
1051 _summary->set_session (_session);
1052 _group_tabs->set_session (_session);
1053 _route_groups->set_session (_session);
1054 _regions->set_session (_session);
1055 _snapshots->set_session (_session);
1056 _routes->set_session (_session);
1057 _locations->set_session (_session);
1059 if (rhythm_ferret) {
1060 rhythm_ferret->set_session (_session);
1063 if (analysis_window) {
1064 analysis_window->set_session (_session);
1068 sfbrowser->set_session (_session);
1071 compute_fixed_ruler_scale ();
1073 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1074 set_state (*node, Stateful::loading_state_version);
1076 /* catch up with the playhead */
1078 _session->request_locate (playhead_cursor->current_frame);
1079 _pending_initial_locate = true;
1083 /* These signals can all be emitted by a non-GUI thread. Therefore the
1084 handlers for them must not attempt to directly interact with the GUI,
1085 but use Gtkmm2ext::UI::instance()->call_slot();
1088 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1089 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1090 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1091 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1092 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1093 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1094 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1095 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1096 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1097 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1098 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1099 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1100 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1101 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1103 if (Profile->get_sae()) {
1108 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1109 nudge_clock.set_mode(AudioClock::BBT);
1110 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1113 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1116 playhead_cursor->canvas_item.show ();
1118 Location* loc = _session->locations()->auto_loop_location();
1120 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1121 if (loc->start() == loc->end()) {
1122 loc->set_end (loc->start() + 1);
1124 _session->locations()->add (loc, false);
1125 _session->set_auto_loop_location (loc);
1128 loc->set_name (_("Loop"));
1131 loc = _session->locations()->auto_punch_location();
1133 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1134 if (loc->start() == loc->end()) {
1135 loc->set_end (loc->start() + 1);
1137 _session->locations()->add (loc, false);
1138 _session->set_auto_punch_location (loc);
1141 loc->set_name (_("Punch"));
1144 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1145 Config->map_parameters (pc);
1146 _session->config.map_parameters (pc);
1148 refresh_location_display ();
1150 restore_ruler_visibility ();
1151 //tempo_map_changed (PropertyChange (0));
1152 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1154 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1155 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1158 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1159 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1162 switch (_snap_type) {
1163 case SnapToRegionStart:
1164 case SnapToRegionEnd:
1165 case SnapToRegionSync:
1166 case SnapToRegionBoundary:
1167 build_region_boundary_cache ();
1174 /* register for undo history */
1175 _session->register_with_memento_command_factory(_id, this);
1177 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1179 start_updating_meters ();
1183 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1185 if (a->get_name() == "RegionMenu") {
1186 /* When the main menu's region menu is opened, we setup the actions so that they look right
1187 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1188 so we resensitize all region actions when the entered regionview or the region selection
1189 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1190 happens after the region context menu is opened. So we set a flag here, too.
1194 sensitize_the_right_region_actions ();
1195 _last_region_menu_was_main = true;
1199 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1201 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1203 using namespace Menu_Helpers;
1204 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1207 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1211 MenuList& items (fade_context_menu.items());
1215 switch (item_type) {
1217 case FadeInHandleItem:
1218 if (arv->audio_region()->fade_in_active()) {
1219 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1221 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1224 items.push_back (SeparatorElem());
1226 if (Profile->get_sae()) {
1228 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1229 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1236 *_fade_in_images[FadeLinear],
1237 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1241 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1246 *_fade_in_images[FadeFast],
1247 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1250 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1255 *_fade_in_images[FadeLogB],
1256 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1259 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1264 *_fade_in_images[FadeLogA],
1265 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1268 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1273 *_fade_in_images[FadeSlow],
1274 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1277 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1283 case FadeOutHandleItem:
1284 if (arv->audio_region()->fade_out_active()) {
1285 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1287 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1290 items.push_back (SeparatorElem());
1292 if (Profile->get_sae()) {
1293 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1294 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1300 *_fade_out_images[FadeLinear],
1301 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1305 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1310 *_fade_out_images[FadeFast],
1311 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1314 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1319 *_fade_out_images[FadeLogB],
1320 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1323 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1328 *_fade_out_images[FadeLogA],
1329 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1332 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1337 *_fade_out_images[FadeSlow],
1338 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1341 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1347 fatal << _("programming error: ")
1348 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1353 fade_context_menu.popup (button, time);
1357 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1359 using namespace Menu_Helpers;
1360 Menu* (Editor::*build_menu_function)();
1363 switch (item_type) {
1365 case RegionViewName:
1366 case RegionViewNameHighlight:
1367 case LeftFrameHandle:
1368 case RightFrameHandle:
1369 if (with_selection) {
1370 build_menu_function = &Editor::build_track_selection_context_menu;
1372 build_menu_function = &Editor::build_track_region_context_menu;
1377 if (with_selection) {
1378 build_menu_function = &Editor::build_track_selection_context_menu;
1380 build_menu_function = &Editor::build_track_context_menu;
1384 case CrossfadeViewItem:
1385 build_menu_function = &Editor::build_track_crossfade_context_menu;
1389 if (clicked_routeview->track()) {
1390 build_menu_function = &Editor::build_track_context_menu;
1392 build_menu_function = &Editor::build_track_bus_context_menu;
1397 /* probably shouldn't happen but if it does, we don't care */
1401 menu = (this->*build_menu_function)();
1402 menu->set_name ("ArdourContextMenu");
1404 /* now handle specific situations */
1406 switch (item_type) {
1408 case RegionViewName:
1409 case RegionViewNameHighlight:
1410 case LeftFrameHandle:
1411 case RightFrameHandle:
1412 if (!with_selection) {
1413 if (region_edit_menu_split_item) {
1414 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1415 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1417 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1420 if (region_edit_menu_split_multichannel_item) {
1421 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1422 region_edit_menu_split_multichannel_item->set_sensitive (true);
1424 region_edit_menu_split_multichannel_item->set_sensitive (false);
1433 case CrossfadeViewItem:
1440 /* probably shouldn't happen but if it does, we don't care */
1444 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1446 /* Bounce to disk */
1448 using namespace Menu_Helpers;
1449 MenuList& edit_items = menu->items();
1451 edit_items.push_back (SeparatorElem());
1453 switch (clicked_routeview->audio_track()->freeze_state()) {
1454 case AudioTrack::NoFreeze:
1455 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1458 case AudioTrack::Frozen:
1459 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1462 case AudioTrack::UnFrozen:
1463 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1469 if (item_type == StreamItem && clicked_routeview) {
1470 clicked_routeview->build_underlay_menu(menu);
1473 /* When the region menu is opened, we setup the actions so that they look right
1476 sensitize_the_right_region_actions ();
1477 _last_region_menu_was_main = false;
1479 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1480 menu->popup (button, time);
1484 Editor::build_track_context_menu ()
1486 using namespace Menu_Helpers;
1488 MenuList& edit_items = track_context_menu.items();
1491 add_dstream_context_items (edit_items);
1492 return &track_context_menu;
1496 Editor::build_track_bus_context_menu ()
1498 using namespace Menu_Helpers;
1500 MenuList& edit_items = track_context_menu.items();
1503 add_bus_context_items (edit_items);
1504 return &track_context_menu;
1508 Editor::build_track_region_context_menu ()
1510 using namespace Menu_Helpers;
1511 MenuList& edit_items = track_region_context_menu.items();
1514 /* we've just cleared the track region context menu, so the menu that these
1515 two items were on will have disappeared; stop them dangling.
1517 region_edit_menu_split_item = 0;
1518 region_edit_menu_split_multichannel_item = 0;
1520 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1523 boost::shared_ptr<Track> tr;
1524 boost::shared_ptr<Playlist> pl;
1526 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1527 mode and so offering region context is somewhat confusing.
1529 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1530 framepos_t const framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1531 uint32_t regions_at = pl->count_regions_at (framepos);
1532 add_region_context_items (edit_items, regions_at > 1);
1536 add_dstream_context_items (edit_items);
1538 return &track_region_context_menu;
1542 Editor::build_track_crossfade_context_menu ()
1544 using namespace Menu_Helpers;
1545 MenuList& edit_items = track_crossfade_context_menu.items();
1546 edit_items.clear ();
1548 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1551 boost::shared_ptr<Track> tr;
1552 boost::shared_ptr<Playlist> pl;
1553 boost::shared_ptr<AudioPlaylist> apl;
1555 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1557 AudioPlaylist::Crossfades xfades;
1559 apl->crossfades_at (get_preferred_edit_position (), xfades);
1561 bool many = xfades.size() > 1;
1563 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1564 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1567 framepos_t framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1568 uint32_t regions_at = pl->count_regions_at (framepos);
1569 add_region_context_items (edit_items, regions_at > 1);
1573 add_dstream_context_items (edit_items);
1575 return &track_crossfade_context_menu;
1579 Editor::analyze_region_selection ()
1581 if (analysis_window == 0) {
1582 analysis_window = new AnalysisWindow();
1585 analysis_window->set_session(_session);
1587 analysis_window->show_all();
1590 analysis_window->set_regionmode();
1591 analysis_window->analyze();
1593 analysis_window->present();
1597 Editor::analyze_range_selection()
1599 if (analysis_window == 0) {
1600 analysis_window = new AnalysisWindow();
1603 analysis_window->set_session(_session);
1605 analysis_window->show_all();
1608 analysis_window->set_rangemode();
1609 analysis_window->analyze();
1611 analysis_window->present();
1615 Editor::build_track_selection_context_menu ()
1617 using namespace Menu_Helpers;
1618 MenuList& edit_items = track_selection_context_menu.items();
1619 edit_items.clear ();
1621 add_selection_context_items (edit_items);
1622 // edit_items.push_back (SeparatorElem());
1623 // add_dstream_context_items (edit_items);
1625 return &track_selection_context_menu;
1628 /** Add context menu items relevant to crossfades.
1629 * @param edit_items List to add the items to.
1632 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1634 using namespace Menu_Helpers;
1635 Menu *xfade_menu = manage (new Menu);
1636 MenuList& items = xfade_menu->items();
1637 xfade_menu->set_name ("ArdourContextMenu");
1640 if (xfade->active()) {
1646 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1647 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1649 if (xfade->can_follow_overlap()) {
1651 if (xfade->following_overlap()) {
1652 str = _("Convert to Short");
1654 str = _("Convert to Full");
1657 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1661 str = xfade->out()->name();
1663 str += xfade->in()->name();
1665 str = _("Crossfade");
1668 edit_items.push_back (MenuElem (str, *xfade_menu));
1669 edit_items.push_back (SeparatorElem());
1673 Editor::xfade_edit_left_region ()
1675 if (clicked_crossfadeview) {
1676 clicked_crossfadeview->left_view.show_region_editor ();
1681 Editor::xfade_edit_right_region ()
1683 if (clicked_crossfadeview) {
1684 clicked_crossfadeview->right_view.show_region_editor ();
1689 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1691 using namespace Menu_Helpers;
1693 /* OK, stick the region submenu at the top of the list, and then add
1697 /* we have to hack up the region name because "_" has a special
1698 meaning for menu titles.
1701 RegionSelection rs = get_regions_from_selection_and_entered ();
1703 string::size_type pos = 0;
1704 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1706 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1707 menu_item_name.replace (pos, 1, "__");
1711 if (_popup_region_menu_item == 0) {
1712 _popup_region_menu_item = new MenuItem (menu_item_name);
1713 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1714 _popup_region_menu_item->show ();
1716 _popup_region_menu_item->set_label (menu_item_name);
1719 edit_items.push_back (*_popup_region_menu_item);
1720 if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1721 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1723 edit_items.push_back (SeparatorElem());
1726 /** Add context menu items relevant to selection ranges.
1727 * @param edit_items List to add the items to.
1730 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1732 using namespace Menu_Helpers;
1734 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1735 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1737 edit_items.push_back (SeparatorElem());
1738 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1740 if (!selection->regions.empty()) {
1741 edit_items.push_back (SeparatorElem());
1742 edit_items.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1743 edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1746 edit_items.push_back (SeparatorElem());
1747 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1748 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1750 edit_items.push_back (SeparatorElem());
1751 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1753 edit_items.push_back (SeparatorElem());
1754 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1755 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1757 edit_items.push_back (SeparatorElem());
1758 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1760 edit_items.push_back (SeparatorElem());
1761 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1762 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1763 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1765 edit_items.push_back (SeparatorElem());
1766 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1767 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1768 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1769 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1770 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1775 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1777 using namespace Menu_Helpers;
1781 Menu *play_menu = manage (new Menu);
1782 MenuList& play_items = play_menu->items();
1783 play_menu->set_name ("ArdourContextMenu");
1785 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1786 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1787 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1788 play_items.push_back (SeparatorElem());
1789 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1791 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1795 Menu *select_menu = manage (new Menu);
1796 MenuList& select_items = select_menu->items();
1797 select_menu->set_name ("ArdourContextMenu");
1799 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1800 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1801 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1802 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1803 select_items.push_back (SeparatorElem());
1804 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1805 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1806 select_items.push_back (SeparatorElem());
1807 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1808 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1809 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1810 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1811 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1812 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1813 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1815 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1819 Menu *cutnpaste_menu = manage (new Menu);
1820 MenuList& cutnpaste_items = cutnpaste_menu->items();
1821 cutnpaste_menu->set_name ("ArdourContextMenu");
1823 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1824 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1825 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1827 cutnpaste_items.push_back (SeparatorElem());
1829 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1830 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1832 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1834 /* Adding new material */
1836 edit_items.push_back (SeparatorElem());
1837 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1838 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1842 Menu *nudge_menu = manage (new Menu());
1843 MenuList& nudge_items = nudge_menu->items();
1844 nudge_menu->set_name ("ArdourContextMenu");
1846 edit_items.push_back (SeparatorElem());
1847 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1848 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1849 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1850 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1852 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1856 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1858 using namespace Menu_Helpers;
1862 Menu *play_menu = manage (new Menu);
1863 MenuList& play_items = play_menu->items();
1864 play_menu->set_name ("ArdourContextMenu");
1866 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1867 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1868 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1872 Menu *select_menu = manage (new Menu);
1873 MenuList& select_items = select_menu->items();
1874 select_menu->set_name ("ArdourContextMenu");
1876 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1877 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1878 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1879 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1880 select_items.push_back (SeparatorElem());
1881 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1882 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1883 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1884 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1886 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1890 Menu *cutnpaste_menu = manage (new Menu);
1891 MenuList& cutnpaste_items = cutnpaste_menu->items();
1892 cutnpaste_menu->set_name ("ArdourContextMenu");
1894 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1895 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1896 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1898 Menu *nudge_menu = manage (new Menu());
1899 MenuList& nudge_items = nudge_menu->items();
1900 nudge_menu->set_name ("ArdourContextMenu");
1902 edit_items.push_back (SeparatorElem());
1903 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1904 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1905 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1906 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1908 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1912 Editor::snap_type() const
1918 Editor::snap_mode() const
1924 Editor::set_snap_to (SnapType st)
1926 unsigned int snap_ind = (unsigned int)st;
1930 if (snap_ind > snap_type_strings.size() - 1) {
1932 _snap_type = (SnapType)snap_ind;
1935 string str = snap_type_strings[snap_ind];
1937 if (str != snap_type_selector.get_active_text()) {
1938 snap_type_selector.set_active_text (str);
1943 switch (_snap_type) {
1944 case SnapToBeatDiv32:
1945 case SnapToBeatDiv28:
1946 case SnapToBeatDiv24:
1947 case SnapToBeatDiv20:
1948 case SnapToBeatDiv16:
1949 case SnapToBeatDiv14:
1950 case SnapToBeatDiv12:
1951 case SnapToBeatDiv10:
1952 case SnapToBeatDiv8:
1953 case SnapToBeatDiv7:
1954 case SnapToBeatDiv6:
1955 case SnapToBeatDiv5:
1956 case SnapToBeatDiv4:
1957 case SnapToBeatDiv3:
1958 case SnapToBeatDiv2:
1959 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
1960 update_tempo_based_rulers ();
1963 case SnapToRegionStart:
1964 case SnapToRegionEnd:
1965 case SnapToRegionSync:
1966 case SnapToRegionBoundary:
1967 build_region_boundary_cache ();
1975 SnapChanged (); /* EMIT SIGNAL */
1979 Editor::set_snap_mode (SnapMode mode)
1982 string str = snap_mode_strings[(int)mode];
1984 if (str != snap_mode_selector.get_active_text ()) {
1985 snap_mode_selector.set_active_text (str);
1991 Editor::set_edit_point_preference (EditPoint ep, bool force)
1993 bool changed = (_edit_point != ep);
1996 string str = edit_point_strings[(int)ep];
1998 if (str != edit_point_selector.get_active_text ()) {
1999 edit_point_selector.set_active_text (str);
2002 set_canvas_cursor ();
2004 if (!force && !changed) {
2008 const char* action=NULL;
2010 switch (_edit_point) {
2011 case EditAtPlayhead:
2012 action = "edit-at-playhead";
2014 case EditAtSelectedMarker:
2015 action = "edit-at-marker";
2018 action = "edit-at-mouse";
2022 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2024 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2028 bool in_track_canvas;
2030 if (!mouse_frame (foo, in_track_canvas)) {
2031 in_track_canvas = false;
2034 reset_canvas_action_sensitivity (in_track_canvas);
2040 Editor::set_state (const XMLNode& node, int /*version*/)
2042 const XMLProperty* prop;
2044 int x, y, xoff, yoff;
2047 if ((prop = node.property ("id")) != 0) {
2048 _id = prop->value ();
2051 g.base_width = default_width;
2052 g.base_height = default_height;
2058 if ((geometry = find_named_node (node, "geometry")) != 0) {
2062 if ((prop = geometry->property("x_size")) == 0) {
2063 prop = geometry->property ("x-size");
2066 g.base_width = atoi(prop->value());
2068 if ((prop = geometry->property("y_size")) == 0) {
2069 prop = geometry->property ("y-size");
2072 g.base_height = atoi(prop->value());
2075 if ((prop = geometry->property ("x_pos")) == 0) {
2076 prop = geometry->property ("x-pos");
2079 x = atoi (prop->value());
2082 if ((prop = geometry->property ("y_pos")) == 0) {
2083 prop = geometry->property ("y-pos");
2086 y = atoi (prop->value());
2089 if ((prop = geometry->property ("x_off")) == 0) {
2090 prop = geometry->property ("x-off");
2093 xoff = atoi (prop->value());
2095 if ((prop = geometry->property ("y_off")) == 0) {
2096 prop = geometry->property ("y-off");
2099 yoff = atoi (prop->value());
2103 set_default_size (g.base_width, g.base_height);
2106 if (_session && (prop = node.property ("playhead"))) {
2108 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2109 playhead_cursor->set_position (pos);
2111 playhead_cursor->set_position (0);
2114 if ((prop = node.property ("mixer-width"))) {
2115 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2118 if ((prop = node.property ("zoom-focus"))) {
2119 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2122 if ((prop = node.property ("zoom"))) {
2123 reset_zoom (PBD::atof (prop->value()));
2125 reset_zoom (frames_per_unit);
2128 if ((prop = node.property ("snap-to"))) {
2129 set_snap_to ((SnapType) atoi (prop->value()));
2132 if ((prop = node.property ("snap-mode"))) {
2133 set_snap_mode ((SnapMode) atoi (prop->value()));
2136 if ((prop = node.property ("mouse-mode"))) {
2137 MouseMode m = str2mousemode(prop->value());
2138 set_mouse_mode (m, true);
2140 set_mouse_mode (MouseObject, true);
2143 if ((prop = node.property ("left-frame")) != 0){
2145 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2146 reset_x_origin (pos);
2150 if ((prop = node.property ("y-origin")) != 0) {
2151 reset_y_origin (atof (prop->value ()));
2154 if ((prop = node.property ("internal-edit"))) {
2155 bool yn = string_is_affirmative (prop->value());
2156 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2158 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2159 tact->set_active (!yn);
2160 tact->set_active (yn);
2164 if ((prop = node.property ("join-object-range"))) {
2165 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2168 if ((prop = node.property ("edit-point"))) {
2169 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2172 if ((prop = node.property ("show-measures"))) {
2173 bool yn = string_is_affirmative (prop->value());
2174 _show_measures = yn;
2175 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2177 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2178 /* do it twice to force the change */
2179 tact->set_active (!yn);
2180 tact->set_active (yn);
2184 if ((prop = node.property ("follow-playhead"))) {
2185 bool yn = string_is_affirmative (prop->value());
2186 set_follow_playhead (yn);
2187 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2189 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2190 if (tact->get_active() != yn) {
2191 tact->set_active (yn);
2196 if ((prop = node.property ("stationary-playhead"))) {
2197 bool yn = (prop->value() == "yes");
2198 set_stationary_playhead (yn);
2199 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2201 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2202 if (tact->get_active() != yn) {
2203 tact->set_active (yn);
2208 if ((prop = node.property ("region-list-sort-type"))) {
2209 RegionListSortType st;
2210 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2213 if ((prop = node.property ("xfades-visible"))) {
2214 bool yn = string_is_affirmative (prop->value());
2215 _xfade_visibility = !yn;
2216 // set_xfade_visibility (yn);
2219 if ((prop = node.property ("show-editor-mixer"))) {
2221 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2224 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2225 bool yn = string_is_affirmative (prop->value());
2227 /* do it twice to force the change */
2229 tact->set_active (!yn);
2230 tact->set_active (yn);
2233 if ((prop = node.property ("show-editor-list"))) {
2235 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2238 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2239 bool yn = string_is_affirmative (prop->value());
2241 /* do it twice to force the change */
2243 tact->set_active (!yn);
2244 tact->set_active (yn);
2247 if ((prop = node.property (X_("editor-list-page")))) {
2248 the_notebook.set_current_page (atoi (prop->value ()));
2251 if ((prop = node.property (X_("show-marker-lines")))) {
2252 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2254 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2255 bool yn = string_is_affirmative (prop->value ());
2257 tact->set_active (!yn);
2258 tact->set_active (yn);
2261 XMLNodeList children = node.children ();
2262 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2263 selection->set_state (**i, Stateful::current_state_version);
2264 _regions->set_state (**i);
2271 Editor::get_state ()
2273 XMLNode* node = new XMLNode ("Editor");
2276 _id.print (buf, sizeof (buf));
2277 node->add_property ("id", buf);
2279 if (is_realized()) {
2280 Glib::RefPtr<Gdk::Window> win = get_window();
2282 int x, y, xoff, yoff, width, height;
2283 win->get_root_origin(x, y);
2284 win->get_position(xoff, yoff);
2285 win->get_size(width, height);
2287 XMLNode* geometry = new XMLNode ("geometry");
2289 snprintf(buf, sizeof(buf), "%d", width);
2290 geometry->add_property("x-size", string(buf));
2291 snprintf(buf, sizeof(buf), "%d", height);
2292 geometry->add_property("y-size", string(buf));
2293 snprintf(buf, sizeof(buf), "%d", x);
2294 geometry->add_property("x-pos", string(buf));
2295 snprintf(buf, sizeof(buf), "%d", y);
2296 geometry->add_property("y-pos", string(buf));
2297 snprintf(buf, sizeof(buf), "%d", xoff);
2298 geometry->add_property("x-off", string(buf));
2299 snprintf(buf, sizeof(buf), "%d", yoff);
2300 geometry->add_property("y-off", string(buf));
2301 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2302 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2303 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2304 geometry->add_property("edit-vertical-pane-pos", string(buf));
2306 node->add_child_nocopy (*geometry);
2309 maybe_add_mixer_strip_width (*node);
2311 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2312 node->add_property ("zoom-focus", buf);
2313 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2314 node->add_property ("zoom", buf);
2315 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2316 node->add_property ("snap-to", buf);
2317 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2318 node->add_property ("snap-mode", buf);
2320 node->add_property ("edit-point", enum_2_string (_edit_point));
2322 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2323 node->add_property ("playhead", buf);
2324 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2325 node->add_property ("left-frame", buf);
2326 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2327 node->add_property ("y-origin", buf);
2329 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2330 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2331 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2332 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2333 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2334 node->add_property ("mouse-mode", enum2str(mouse_mode));
2335 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2336 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2338 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2340 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2341 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2344 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2346 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2347 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2350 snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
2351 node->add_property (X_("editor-list-page"), buf);
2353 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2355 node->add_child_nocopy (selection->get_state ());
2356 node->add_child_nocopy (_regions->get_state ());
2363 /** @param y y offset from the top of all trackviews.
2364 * @return pair: TimeAxisView that y is over, layer index.
2365 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2366 * in stacked region display mode, otherwise 0.
2368 std::pair<TimeAxisView *, layer_t>
2369 Editor::trackview_by_y_position (double y)
2371 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2373 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2379 return std::make_pair ( (TimeAxisView *) 0, 0);
2382 /** Snap a position to the grid, if appropriate, taking into account current
2383 * grid settings and also the state of any snap modifier keys that may be pressed.
2384 * @param start Position to snap.
2385 * @param event Event to get current key modifier information from, or 0.
2388 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2390 if (!_session || !event) {
2394 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2395 if (_snap_mode == SnapOff) {
2396 snap_to_internal (start, direction, for_mark);
2399 if (_snap_mode != SnapOff) {
2400 snap_to_internal (start, direction, for_mark);
2406 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2408 if (!_session || _snap_mode == SnapOff) {
2412 snap_to_internal (start, direction, for_mark);
2416 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2418 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2419 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2421 switch (_snap_type) {
2422 case SnapToTimecodeFrame:
2423 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2424 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2426 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2430 case SnapToTimecodeSeconds:
2431 if (_session->config.get_timecode_offset_negative()) {
2432 start += _session->config.get_timecode_offset ();
2434 start -= _session->config.get_timecode_offset ();
2436 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2437 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2439 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2442 if (_session->config.get_timecode_offset_negative()) {
2443 start -= _session->config.get_timecode_offset ();
2445 start += _session->config.get_timecode_offset ();
2449 case SnapToTimecodeMinutes:
2450 if (_session->config.get_timecode_offset_negative()) {
2451 start += _session->config.get_timecode_offset ();
2453 start -= _session->config.get_timecode_offset ();
2455 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2456 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2458 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2460 if (_session->config.get_timecode_offset_negative()) {
2461 start -= _session->config.get_timecode_offset ();
2463 start += _session->config.get_timecode_offset ();
2467 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2473 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2475 const framepos_t one_second = _session->frame_rate();
2476 const framepos_t one_minute = _session->frame_rate() * 60;
2477 framepos_t presnap = start;
2481 switch (_snap_type) {
2482 case SnapToTimecodeFrame:
2483 case SnapToTimecodeSeconds:
2484 case SnapToTimecodeMinutes:
2485 return timecode_snap_to_internal (start, direction, for_mark);
2488 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2489 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2491 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2496 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2497 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2499 start = (framepos_t) floor ((double) start / one_second) * one_second;
2504 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2505 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2507 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2512 start = _session->tempo_map().round_to_bar (start, direction);
2516 start = _session->tempo_map().round_to_beat (start, direction);
2519 case SnapToBeatDiv32:
2520 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2522 case SnapToBeatDiv28:
2523 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2525 case SnapToBeatDiv24:
2526 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2528 case SnapToBeatDiv20:
2529 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2531 case SnapToBeatDiv16:
2532 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2534 case SnapToBeatDiv14:
2535 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2537 case SnapToBeatDiv12:
2538 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2540 case SnapToBeatDiv10:
2541 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2543 case SnapToBeatDiv8:
2544 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2546 case SnapToBeatDiv7:
2547 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2549 case SnapToBeatDiv6:
2550 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2552 case SnapToBeatDiv5:
2553 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2555 case SnapToBeatDiv4:
2556 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2558 case SnapToBeatDiv3:
2559 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2561 case SnapToBeatDiv2:
2562 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2570 _session->locations()->marks_either_side (start, before, after);
2572 if (before == max_framepos) {
2574 } else if (after == max_framepos) {
2576 } else if (before != max_framepos && after != max_framepos) {
2577 /* have before and after */
2578 if ((start - before) < (after - start)) {
2587 case SnapToRegionStart:
2588 case SnapToRegionEnd:
2589 case SnapToRegionSync:
2590 case SnapToRegionBoundary:
2591 if (!region_boundary_cache.empty()) {
2593 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2594 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2596 if (direction > 0) {
2597 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2599 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2602 if (next != region_boundary_cache.begin ()) {
2607 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2608 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2610 if (start > (p + n) / 2) {
2619 switch (_snap_mode) {
2625 if (presnap > start) {
2626 if (presnap > (start + unit_to_frame(snap_threshold))) {
2630 } else if (presnap < start) {
2631 if (presnap < (start - unit_to_frame(snap_threshold))) {
2637 /* handled at entry */
2645 Editor::setup_toolbar ()
2649 /* Mode Buttons (tool selection) */
2651 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2652 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2653 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2654 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2655 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2656 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2657 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2658 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2660 HBox* mode_box = manage(new HBox);
2661 mode_box->set_border_width (2);
2662 mode_box->set_spacing(4);
2664 /* table containing mode buttons */
2666 HBox* mouse_mode_button_box = manage (new HBox ());
2668 if (Profile->get_sae()) {
2669 mouse_mode_button_box->pack_start (mouse_move_button);
2671 mouse_mode_button_box->pack_start (mouse_move_button);
2672 mouse_mode_button_box->pack_start (join_object_range_button);
2673 mouse_mode_button_box->pack_start (mouse_select_button);
2676 mouse_mode_button_box->pack_start (mouse_zoom_button);
2678 if (!Profile->get_sae()) {
2679 mouse_mode_button_box->pack_start (mouse_gain_button);
2682 mouse_mode_button_box->pack_start (mouse_timefx_button);
2683 mouse_mode_button_box->pack_start (mouse_audition_button);
2684 mouse_mode_button_box->pack_start (internal_edit_button);
2686 vector<string> edit_mode_strings;
2687 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2688 if (!Profile->get_sae()) {
2689 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2691 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2693 edit_mode_selector.set_name ("EditModeSelector");
2694 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2695 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2697 mode_box->pack_start (edit_mode_selector);
2698 mode_box->pack_start (*mouse_mode_button_box);
2700 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2701 _mouse_mode_tearoff->set_name ("MouseModeBase");
2702 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2704 if (Profile->get_sae()) {
2705 _mouse_mode_tearoff->set_can_be_torn_off (false);
2708 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2709 &_mouse_mode_tearoff->tearoff_window()));
2710 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2711 &_mouse_mode_tearoff->tearoff_window(), 1));
2712 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2713 &_mouse_mode_tearoff->tearoff_window()));
2714 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2715 &_mouse_mode_tearoff->tearoff_window(), 1));
2717 mouse_move_button.set_mode (false);
2718 mouse_select_button.set_mode (false);
2719 mouse_gain_button.set_mode (false);
2720 mouse_zoom_button.set_mode (false);
2721 mouse_timefx_button.set_mode (false);
2722 mouse_audition_button.set_mode (false);
2723 join_object_range_button.set_mode (false);
2725 mouse_move_button.set_name ("MouseModeButton");
2726 mouse_select_button.set_name ("MouseModeButton");
2727 mouse_gain_button.set_name ("MouseModeButton");
2728 mouse_zoom_button.set_name ("MouseModeButton");
2729 mouse_timefx_button.set_name ("MouseModeButton");
2730 mouse_audition_button.set_name ("MouseModeButton");
2731 internal_edit_button.set_name ("MouseModeButton");
2732 join_object_range_button.set_name ("MouseModeButton");
2734 mouse_move_button.unset_flags (CAN_FOCUS);
2735 mouse_select_button.unset_flags (CAN_FOCUS);
2736 mouse_gain_button.unset_flags (CAN_FOCUS);
2737 mouse_zoom_button.unset_flags (CAN_FOCUS);
2738 mouse_timefx_button.unset_flags (CAN_FOCUS);
2739 mouse_audition_button.unset_flags (CAN_FOCUS);
2740 internal_edit_button.unset_flags (CAN_FOCUS);
2741 join_object_range_button.unset_flags (CAN_FOCUS);
2745 _zoom_box.set_spacing (1);
2746 _zoom_box.set_border_width (0);
2748 zoom_in_button.set_name ("EditorTimeButton");
2749 zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2750 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2752 zoom_out_button.set_name ("EditorTimeButton");
2753 zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2754 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2756 zoom_out_full_button.set_name ("EditorTimeButton");
2757 zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2758 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2760 zoom_focus_selector.set_name ("ZoomFocusSelector");
2761 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2762 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2764 _zoom_box.pack_start (zoom_out_button, false, false);
2765 _zoom_box.pack_start (zoom_in_button, false, false);
2766 _zoom_box.pack_start (zoom_out_full_button, false, false);
2768 _zoom_box.pack_start (zoom_focus_selector);
2770 /* Track zoom buttons */
2771 tav_expand_button.set_name ("TrackHeightButton");
2772 tav_expand_button.set_size_request(-1,20);
2773 tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2774 tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2776 tav_shrink_button.set_name ("TrackHeightButton");
2777 tav_shrink_button.set_size_request(-1,20);
2778 tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2779 tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2781 _zoom_box.pack_start (tav_shrink_button);
2782 _zoom_box.pack_start (tav_expand_button);
2784 _zoom_tearoff = manage (new TearOff (_zoom_box));
2786 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2787 &_zoom_tearoff->tearoff_window()));
2788 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2789 &_zoom_tearoff->tearoff_window(), 0));
2790 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2791 &_zoom_tearoff->tearoff_window()));
2792 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2793 &_zoom_tearoff->tearoff_window(), 0));
2795 snap_box.set_spacing (1);
2796 snap_box.set_border_width (2);
2798 snap_type_selector.set_name ("SnapTypeSelector");
2799 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2800 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2802 snap_mode_selector.set_name ("SnapModeSelector");
2803 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2804 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2806 edit_point_selector.set_name ("EditPointSelector");
2807 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2808 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2810 snap_box.pack_start (snap_mode_selector, false, false);
2811 snap_box.pack_start (snap_type_selector, false, false);
2812 snap_box.pack_start (edit_point_selector, false, false);
2816 HBox *nudge_box = manage (new HBox);
2817 nudge_box->set_spacing(1);
2818 nudge_box->set_border_width (2);
2820 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2821 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2823 nudge_box->pack_start (nudge_backward_button, false, false);
2824 nudge_box->pack_start (nudge_forward_button, false, false);
2825 nudge_box->pack_start (nudge_clock, false, false);
2828 /* Pack everything in... */
2830 HBox* hbox = manage (new HBox);
2831 hbox->set_spacing(10);
2833 _tools_tearoff = manage (new TearOff (*hbox));
2834 _tools_tearoff->set_name ("MouseModeBase");
2835 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2837 if (Profile->get_sae()) {
2838 _tools_tearoff->set_can_be_torn_off (false);
2841 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2842 &_tools_tearoff->tearoff_window()));
2843 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2844 &_tools_tearoff->tearoff_window(), 0));
2845 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2846 &_tools_tearoff->tearoff_window()));
2847 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2848 &_tools_tearoff->tearoff_window(), 0));
2850 toolbar_hbox.set_spacing (10);
2851 toolbar_hbox.set_border_width (1);
2853 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2854 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2855 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2857 hbox->pack_start (snap_box, false, false);
2858 hbox->pack_start (*nudge_box, false, false);
2859 hbox->pack_start (panic_box, false, false);
2863 toolbar_base.set_name ("ToolBarBase");
2864 toolbar_base.add (toolbar_hbox);
2866 toolbar_frame.set_shadow_type (SHADOW_OUT);
2867 toolbar_frame.set_name ("BaseFrame");
2868 toolbar_frame.add (toolbar_base);
2872 Editor::setup_tooltips ()
2874 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2875 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2876 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2877 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2878 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2879 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2880 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2881 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2882 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2883 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2884 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2885 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2886 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2887 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2888 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2889 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2890 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2891 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2892 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2893 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2894 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2895 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2899 Editor::midi_panic ()
2901 cerr << "MIDI panic\n";
2904 _session->midi_panic();
2909 Editor::setup_midi_toolbar ()
2913 /* Midi sound notes */
2914 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
2915 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
2916 midi_sound_notes.unset_flags (CAN_FOCUS);
2920 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
2921 midi_panic_button.set_name("MidiPanicButton");
2922 act->connect_proxy (midi_panic_button);
2924 panic_box.pack_start (midi_sound_notes , true, true);
2925 panic_box.pack_start (midi_panic_button, true, true);
2929 Editor::convert_drop_to_paths (
2930 vector<string>& paths,
2931 const RefPtr<Gdk::DragContext>& /*context*/,
2934 const SelectionData& data,
2938 if (_session == 0) {
2942 vector<string> uris = data.get_uris();
2946 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2947 are actually URI lists. So do it by hand.
2950 if (data.get_target() != "text/plain") {
2954 /* Parse the "uri-list" format that Nautilus provides,
2955 where each pathname is delimited by \r\n.
2957 THERE MAY BE NO NULL TERMINATING CHAR!!!
2960 string txt = data.get_text();
2964 p = (const char *) malloc (txt.length() + 1);
2965 txt.copy ((char *) p, txt.length(), 0);
2966 ((char*)p)[txt.length()] = '\0';
2972 while (g_ascii_isspace (*p))
2976 while (*q && (*q != '\n') && (*q != '\r')) {
2983 while (q > p && g_ascii_isspace (*q))
2988 uris.push_back (string (p, q - p + 1));
2992 p = strchr (p, '\n');
3004 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3006 if ((*i).substr (0,7) == "file://") {
3009 PBD::url_decode (p);
3011 // scan forward past three slashes
3013 string::size_type slashcnt = 0;
3014 string::size_type n = 0;
3015 string::iterator x = p.begin();
3017 while (slashcnt < 3 && x != p.end()) {
3020 } else if (slashcnt == 3) {
3027 if (slashcnt != 3 || x == p.end()) {
3028 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3032 paths.push_back (p.substr (n - 1));
3040 Editor::new_tempo_section ()
3046 Editor::map_transport_state ()
3048 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3050 if (_session && _session->transport_stopped()) {
3051 have_pending_keyboard_selection = false;
3054 update_loop_range_view (true);
3059 Editor::State::State (PublicEditor const * e)
3061 selection = new Selection (e);
3064 Editor::State::~State ()
3070 Editor::begin_reversible_command (string name)
3073 _session->begin_reversible_command (name);
3078 Editor::commit_reversible_command ()
3081 _session->commit_reversible_command ();
3086 Editor::set_route_group_solo (Route& route, bool yn)
3088 RouteGroup *route_group;
3090 if ((route_group = route.route_group()) != 0) {
3091 route_group->apply (&Route::set_solo, yn, this);
3093 route.set_solo (yn, this);
3098 Editor::set_route_group_mute (Route& route, bool yn)
3100 RouteGroup *route_group = 0;
3102 if ((route_group = route.route_group()) != 0) {
3103 route_group->apply (&Route::set_mute, yn, this);
3105 route.set_mute (yn, this);
3110 Editor::history_changed ()
3114 if (undo_action && _session) {
3115 if (_session->undo_depth() == 0) {
3118 label = string_compose(_("Undo (%1)"), _session->next_undo());
3120 undo_action->property_label() = label;
3123 if (redo_action && _session) {
3124 if (_session->redo_depth() == 0) {
3127 label = string_compose(_("Redo (%1)"), _session->next_redo());
3129 redo_action->property_label() = label;
3134 Editor::duplicate_dialog (bool with_dialog)
3138 if (mouse_mode == MouseRange) {
3139 if (selection->time.length() == 0) {
3144 RegionSelection rs = get_regions_from_selection_and_entered ();
3146 if (mouse_mode != MouseRange && rs.empty()) {
3152 ArdourDialog win (_("Duplicate"));
3153 Label label (_("Number of duplications:"));
3154 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3155 SpinButton spinner (adjustment, 0.0, 1);
3158 win.get_vbox()->set_spacing (12);
3159 win.get_vbox()->pack_start (hbox);
3160 hbox.set_border_width (6);
3161 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3163 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3164 place, visually. so do this by hand.
3167 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3168 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3169 spinner.grab_focus();
3175 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3176 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3177 win.set_default_response (RESPONSE_ACCEPT);
3179 win.set_position (WIN_POS_MOUSE);
3181 spinner.grab_focus ();
3183 switch (win.run ()) {
3184 case RESPONSE_ACCEPT:
3190 times = adjustment.get_value();
3193 if (mouse_mode == MouseRange) {
3194 duplicate_selection (times);
3196 duplicate_some_regions (rs, times);
3201 Editor::show_verbose_canvas_cursor ()
3203 verbose_canvas_cursor->raise_to_top();
3204 verbose_canvas_cursor->show();
3205 verbose_cursor_visible = true;
3209 Editor::hide_verbose_canvas_cursor ()
3211 verbose_canvas_cursor->hide();
3212 verbose_cursor_visible = false;
3216 Editor::clamp_verbose_cursor_x (double x)
3221 x = min (_canvas_width - 200.0, x);
3227 Editor::clamp_verbose_cursor_y (double y)
3229 if (y < canvas_timebars_vsize) {
3230 y = canvas_timebars_vsize;
3232 y = min (_canvas_height - 50, y);
3238 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3240 verbose_canvas_cursor->property_text() = txt.c_str();
3245 track_canvas->get_pointer (x, y);
3246 track_canvas->window_to_world (x, y, wx, wy);
3251 /* don't get too close to the edge */
3252 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3253 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3255 show_verbose_canvas_cursor ();
3259 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3261 verbose_canvas_cursor->property_text() = txt.c_str();
3262 /* don't get too close to the edge */
3263 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3264 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3268 Editor::set_verbose_canvas_cursor_text (const string & txt)
3270 verbose_canvas_cursor->property_text() = txt.c_str();
3274 Editor::set_edit_mode (EditMode m)
3276 Config->set_edit_mode (m);
3280 Editor::cycle_edit_mode ()
3282 switch (Config->get_edit_mode()) {
3284 if (Profile->get_sae()) {
3285 Config->set_edit_mode (Lock);
3287 Config->set_edit_mode (Splice);
3291 Config->set_edit_mode (Lock);
3294 Config->set_edit_mode (Slide);
3300 Editor::edit_mode_selection_done ()
3302 Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ()));
3306 Editor::snap_type_selection_done ()
3308 string choice = snap_type_selector.get_active_text();
3309 SnapType snaptype = SnapToBeat;
3311 if (choice == _("Beats/2")) {
3312 snaptype = SnapToBeatDiv2;
3313 } else if (choice == _("Beats/3")) {
3314 snaptype = SnapToBeatDiv3;
3315 } else if (choice == _("Beats/4")) {
3316 snaptype = SnapToBeatDiv4;
3317 } else if (choice == _("Beats/5")) {
3318 snaptype = SnapToBeatDiv5;
3319 } else if (choice == _("Beats/6")) {
3320 snaptype = SnapToBeatDiv6;
3321 } else if (choice == _("Beats/7")) {
3322 snaptype = SnapToBeatDiv7;
3323 } else if (choice == _("Beats/8")) {
3324 snaptype = SnapToBeatDiv8;
3325 } else if (choice == _("Beats/10")) {
3326 snaptype = SnapToBeatDiv10;
3327 } else if (choice == _("Beats/12")) {
3328 snaptype = SnapToBeatDiv12;
3329 } else if (choice == _("Beats/14")) {
3330 snaptype = SnapToBeatDiv14;
3331 } else if (choice == _("Beats/16")) {
3332 snaptype = SnapToBeatDiv16;
3333 } else if (choice == _("Beats/20")) {
3334 snaptype = SnapToBeatDiv20;
3335 } else if (choice == _("Beats/24")) {
3336 snaptype = SnapToBeatDiv24;
3337 } else if (choice == _("Beats/28")) {
3338 snaptype = SnapToBeatDiv28;
3339 } else if (choice == _("Beats/32")) {
3340 snaptype = SnapToBeatDiv32;
3341 } else if (choice == _("Beats")) {
3342 snaptype = SnapToBeat;
3343 } else if (choice == _("Bars")) {
3344 snaptype = SnapToBar;
3345 } else if (choice == _("Marks")) {
3346 snaptype = SnapToMark;
3347 } else if (choice == _("Region starts")) {
3348 snaptype = SnapToRegionStart;
3349 } else if (choice == _("Region ends")) {
3350 snaptype = SnapToRegionEnd;
3351 } else if (choice == _("Region bounds")) {
3352 snaptype = SnapToRegionBoundary;
3353 } else if (choice == _("Region syncs")) {
3354 snaptype = SnapToRegionSync;
3355 } else if (choice == _("CD Frames")) {
3356 snaptype = SnapToCDFrame;
3357 } else if (choice == _("Timecode Frames")) {
3358 snaptype = SnapToTimecodeFrame;
3359 } else if (choice == _("Timecode Seconds")) {
3360 snaptype = SnapToTimecodeSeconds;
3361 } else if (choice == _("Timecode Minutes")) {
3362 snaptype = SnapToTimecodeMinutes;
3363 } else if (choice == _("Seconds")) {
3364 snaptype = SnapToSeconds;
3365 } else if (choice == _("Minutes")) {
3366 snaptype = SnapToMinutes;
3369 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3371 ract->set_active ();
3376 Editor::snap_mode_selection_done ()
3378 string choice = snap_mode_selector.get_active_text();
3379 SnapMode mode = SnapNormal;
3381 if (choice == _("No Grid")) {
3383 } else if (choice == _("Grid")) {
3385 } else if (choice == _("Magnetic")) {
3386 mode = SnapMagnetic;
3389 RefPtr<RadioAction> ract = snap_mode_action (mode);
3392 ract->set_active (true);
3397 Editor::cycle_edit_point (bool with_marker)
3399 switch (_edit_point) {
3401 set_edit_point_preference (EditAtPlayhead);
3403 case EditAtPlayhead:
3405 set_edit_point_preference (EditAtSelectedMarker);
3407 set_edit_point_preference (EditAtMouse);
3410 case EditAtSelectedMarker:
3411 set_edit_point_preference (EditAtMouse);
3417 Editor::edit_point_selection_done ()
3419 string choice = edit_point_selector.get_active_text();
3420 EditPoint ep = EditAtSelectedMarker;
3422 if (choice == _("Marker")) {
3423 set_edit_point_preference (EditAtSelectedMarker);
3424 } else if (choice == _("Playhead")) {
3425 set_edit_point_preference (EditAtPlayhead);
3427 set_edit_point_preference (EditAtMouse);
3430 RefPtr<RadioAction> ract = edit_point_action (ep);
3433 ract->set_active (true);
3438 Editor::zoom_focus_selection_done ()
3440 string choice = zoom_focus_selector.get_active_text();
3441 ZoomFocus focus_type = ZoomFocusLeft;
3443 if (choice == _("Left")) {
3444 focus_type = ZoomFocusLeft;
3445 } else if (choice == _("Right")) {
3446 focus_type = ZoomFocusRight;
3447 } else if (choice == _("Center")) {
3448 focus_type = ZoomFocusCenter;
3449 } else if (choice == _("Playhead")) {
3450 focus_type = ZoomFocusPlayhead;
3451 } else if (choice == _("Mouse")) {
3452 focus_type = ZoomFocusMouse;
3453 } else if (choice == _("Edit point")) {
3454 focus_type = ZoomFocusEdit;
3457 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3460 ract->set_active ();
3465 Editor::edit_controls_button_release (GdkEventButton* ev)
3467 if (Keyboard::is_context_menu_event (ev)) {
3468 ARDOUR_UI::instance()->add_route (this);
3474 Editor::mouse_select_button_release (GdkEventButton* ev)
3476 /* this handles just right-clicks */
3478 if (ev->button != 3) {
3486 Editor::set_zoom_focus (ZoomFocus f)
3488 string str = zoom_focus_strings[(int)f];
3490 if (str != zoom_focus_selector.get_active_text()) {
3491 zoom_focus_selector.set_active_text (str);
3494 if (zoom_focus != f) {
3497 ZoomFocusChanged (); /* EMIT_SIGNAL */
3504 Editor::ensure_float (Window& win)
3506 win.set_transient_for (*this);
3510 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3512 /* recover or initialize pane positions. do this here rather than earlier because
3513 we don't want the positions to change the child allocations, which they seem to do.
3519 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3531 width = default_width;
3532 height = default_height;
3534 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3536 prop = geometry->property ("x-size");
3538 width = atoi (prop->value());
3540 prop = geometry->property ("y-size");
3542 height = atoi (prop->value());
3546 if (which == static_cast<Paned*> (&edit_pane)) {
3548 if (done & Horizontal) {
3552 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3553 /* initial allocation is 90% to canvas, 10% to notebook */
3554 pos = (int) floor (alloc.get_width() * 0.90f);
3555 snprintf (buf, sizeof(buf), "%d", pos);
3557 pos = atoi (prop->value());
3560 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3561 edit_pane.set_position (pos);
3562 pre_maximal_horizontal_pane_position = pos;
3565 done = (Pane) (done | Horizontal);
3567 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3569 if (done & Vertical) {
3573 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3574 /* initial allocation is 90% to canvas, 10% to summary */
3575 pos = (int) floor (alloc.get_height() * 0.90f);
3576 snprintf (buf, sizeof(buf), "%d", pos);
3578 pos = atoi (prop->value());
3581 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3582 editor_summary_pane.set_position (pos);
3583 pre_maximal_vertical_pane_position = pos;
3586 done = (Pane) (done | Vertical);
3591 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3593 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3594 top_hbox.remove (toolbar_frame);
3599 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3601 if (toolbar_frame.get_parent() == 0) {
3602 top_hbox.pack_end (toolbar_frame);
3607 Editor::set_show_measures (bool yn)
3609 if (_show_measures != yn) {
3612 if ((_show_measures = yn) == true) {
3614 tempo_lines->show();
3622 Editor::toggle_follow_playhead ()
3624 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3626 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3627 set_follow_playhead (tact->get_active());
3632 Editor::set_follow_playhead (bool yn)
3634 if (_follow_playhead != yn) {
3635 if ((_follow_playhead = yn) == true) {
3637 reset_x_origin_to_follow_playhead ();
3644 Editor::toggle_stationary_playhead ()
3646 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3648 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3649 set_stationary_playhead (tact->get_active());
3654 Editor::set_stationary_playhead (bool yn)
3656 if (_stationary_playhead != yn) {
3657 if ((_stationary_playhead = yn) == true) {
3659 // FIXME need a 3.0 equivalent of this 2.X call
3660 // update_current_screen ();
3667 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3669 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3671 xfade->set_active (!xfade->active());
3676 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3678 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3680 xfade->set_follow_overlap (!xfade->following_overlap());
3685 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3687 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3693 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3697 switch (cew.run ()) {
3698 case RESPONSE_ACCEPT:
3705 PropertyChange all_crossfade_properties;
3706 all_crossfade_properties.add (ARDOUR::Properties::active);
3707 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3708 xfade->PropertyChanged (all_crossfade_properties);
3712 Editor::playlist_selector () const
3714 return *_playlist_selector;
3718 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3722 switch (_snap_type) {
3727 case SnapToBeatDiv32:
3730 case SnapToBeatDiv28:
3733 case SnapToBeatDiv24:
3736 case SnapToBeatDiv20:
3739 case SnapToBeatDiv16:
3742 case SnapToBeatDiv14:
3745 case SnapToBeatDiv12:
3748 case SnapToBeatDiv10:
3751 case SnapToBeatDiv8:
3754 case SnapToBeatDiv7:
3757 case SnapToBeatDiv6:
3760 case SnapToBeatDiv5:
3763 case SnapToBeatDiv4:
3766 case SnapToBeatDiv3:
3769 case SnapToBeatDiv2:
3775 return _session->tempo_map().meter_at (position).beats_per_bar();
3780 case SnapToTimecodeFrame:
3781 case SnapToTimecodeSeconds:
3782 case SnapToTimecodeMinutes:
3785 case SnapToRegionStart:
3786 case SnapToRegionEnd:
3787 case SnapToRegionSync:
3788 case SnapToRegionBoundary:
3798 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3802 ret = nudge_clock.current_duration (pos);
3803 next = ret + 1; /* XXXX fix me */
3809 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3811 ArdourDialog dialog (_("Playlist Deletion"));
3812 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3813 "If left alone, no audio files used by it will be cleaned.\n"
3814 "If deleted, audio files used by it alone by will cleaned."),
3817 dialog.set_position (WIN_POS_CENTER);
3818 dialog.get_vbox()->pack_start (label);
3822 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3823 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3824 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3826 switch (dialog.run ()) {
3827 case RESPONSE_ACCEPT:
3828 /* delete the playlist */
3832 case RESPONSE_REJECT:
3833 /* keep the playlist */
3845 Editor::audio_region_selection_covers (framepos_t where)
3847 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3848 if ((*a)->region()->covers (where)) {
3857 Editor::prepare_for_cleanup ()
3859 cut_buffer->clear_regions ();
3860 cut_buffer->clear_playlists ();
3862 selection->clear_regions ();
3863 selection->clear_playlists ();
3865 _regions->suspend_redisplay ();
3869 Editor::finish_cleanup ()
3871 _regions->resume_redisplay ();
3875 Editor::transport_loop_location()
3878 return _session->locations()->auto_loop_location();
3885 Editor::transport_punch_location()
3888 return _session->locations()->auto_punch_location();
3895 Editor::control_layout_scroll (GdkEventScroll* ev)
3897 if (Keyboard::some_magic_widget_has_focus()) {
3901 switch (ev->direction) {
3903 scroll_tracks_up_line ();
3907 case GDK_SCROLL_DOWN:
3908 scroll_tracks_down_line ();
3912 /* no left/right handling yet */
3920 Editor::session_state_saved (string)
3923 _snapshots->redisplay ();
3927 Editor::maximise_editing_space ()
3929 _mouse_mode_tearoff->set_visible (false);
3930 _tools_tearoff->set_visible (false);
3931 _zoom_tearoff->set_visible (false);
3933 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3934 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3935 pre_maximal_editor_width = this->get_width ();
3936 pre_maximal_editor_height = this->get_height ();
3938 if (post_maximal_horizontal_pane_position == 0) {
3939 post_maximal_horizontal_pane_position = edit_pane.get_width();
3942 if (post_maximal_vertical_pane_position == 0) {
3943 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3948 if (post_maximal_editor_width) {
3949 edit_pane.set_position (post_maximal_horizontal_pane_position -
3950 abs(post_maximal_editor_width - pre_maximal_editor_width));
3952 edit_pane.set_position (post_maximal_horizontal_pane_position);
3955 if (post_maximal_editor_height) {
3956 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
3957 abs(post_maximal_editor_height - pre_maximal_editor_height));
3959 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
3962 if (Config->get_keep_tearoffs()) {
3963 _mouse_mode_tearoff->set_visible (true);
3964 _tools_tearoff->set_visible (true);
3965 _zoom_tearoff->set_visible (true);
3971 Editor::restore_editing_space ()
3973 // user changed width/height of panes during fullscreen
3975 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
3976 post_maximal_horizontal_pane_position = edit_pane.get_position();
3979 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
3980 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
3985 _mouse_mode_tearoff->set_visible (true);
3986 _tools_tearoff->set_visible (true);
3987 _zoom_tearoff->set_visible (true);
3988 post_maximal_editor_width = this->get_width();
3989 post_maximal_editor_height = this->get_height();
3991 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
3992 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
3996 * Make new playlists for a given track and also any others that belong
3997 * to the same active route group with the `edit' property.
4002 Editor::new_playlists (TimeAxisView* v)
4004 begin_reversible_command (_("new playlists"));
4005 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4006 _session->playlists->get (playlists);
4007 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4008 commit_reversible_command ();
4012 * Use a copy of the current playlist for a given track and also any others that belong
4013 * to the same active route group with the `edit' property.
4018 Editor::copy_playlists (TimeAxisView* v)
4020 begin_reversible_command (_("copy playlists"));
4021 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4022 _session->playlists->get (playlists);
4023 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4024 commit_reversible_command ();
4027 /** Clear the current playlist for a given track and also any others that belong
4028 * to the same active route group with the `edit' property.
4033 Editor::clear_playlists (TimeAxisView* v)
4035 begin_reversible_command (_("clear playlists"));
4036 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4037 _session->playlists->get (playlists);
4038 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4039 commit_reversible_command ();
4043 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4045 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4049 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4051 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4055 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4057 atv.clear_playlist ();
4061 Editor::on_key_press_event (GdkEventKey* ev)
4063 return key_press_focus_accelerator_handler (*this, ev);
4067 Editor::on_key_release_event (GdkEventKey* ev)
4069 return Gtk::Window::on_key_release_event (ev);
4070 // return key_press_focus_accelerator_handler (*this, ev);
4073 /** Queue up a change to the viewport x origin.
4074 * @param frame New x origin.
4077 Editor::reset_x_origin (framepos_t frame)
4079 queue_visual_change (frame);
4083 Editor::reset_y_origin (double y)
4085 queue_visual_change_y (y);
4089 Editor::reset_zoom (double fpu)
4091 queue_visual_change (fpu);
4095 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4097 reset_x_origin (frame);
4100 if (!no_save_visual) {
4101 undo_visual_stack.push_back (current_visual_state(false));
4105 Editor::VisualState*
4106 Editor::current_visual_state (bool with_tracks)
4108 VisualState* vs = new VisualState;
4109 vs->y_position = vertical_adjustment.get_value();
4110 vs->frames_per_unit = frames_per_unit;
4111 vs->leftmost_frame = leftmost_frame;
4112 vs->zoom_focus = zoom_focus;
4115 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4116 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4124 Editor::undo_visual_state ()
4126 if (undo_visual_stack.empty()) {
4130 redo_visual_stack.push_back (current_visual_state());
4132 VisualState* vs = undo_visual_stack.back();
4133 undo_visual_stack.pop_back();
4134 use_visual_state (*vs);
4138 Editor::redo_visual_state ()
4140 if (redo_visual_stack.empty()) {
4144 undo_visual_stack.push_back (current_visual_state());
4146 VisualState* vs = redo_visual_stack.back();
4147 redo_visual_stack.pop_back();
4148 use_visual_state (*vs);
4152 Editor::swap_visual_state ()
4154 if (undo_visual_stack.empty()) {
4155 redo_visual_state ();
4157 undo_visual_state ();
4162 Editor::use_visual_state (VisualState& vs)
4164 no_save_visual = true;
4166 _routes->suspend_redisplay ();
4168 vertical_adjustment.set_value (vs.y_position);
4170 set_zoom_focus (vs.zoom_focus);
4171 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4173 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4174 TrackViewList::iterator t;
4176 /* check if the track still exists - it could have been deleted */
4178 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4179 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4184 if (!vs.track_states.empty()) {
4185 _routes->update_visibility ();
4188 _routes->resume_redisplay ();
4190 no_save_visual = false;
4194 Editor::set_frames_per_unit (double fpu)
4196 /* this is the core function that controls the zoom level of the canvas. it is called
4197 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4200 if (fpu == frames_per_unit) {
4209 /* don't allow zooms that fit more than the maximum number
4210 of frames into an 800 pixel wide space.
4213 if (max_framepos / fpu < 800.0) {
4218 tempo_lines->tempo_map_changed();
4220 frames_per_unit = fpu;
4225 Editor::post_zoom ()
4227 // convert fpu to frame count
4229 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4231 if (frames_per_unit != zoom_range_clock.current_duration()) {
4232 zoom_range_clock.set (frames);
4235 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4236 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4237 (*i)->reshow_selection (selection->time);
4241 ZoomChanged (); /* EMIT_SIGNAL */
4243 //reset_scrolling_region ();
4245 if (playhead_cursor) {
4246 playhead_cursor->set_position (playhead_cursor->current_frame);
4249 refresh_location_display();
4250 _summary->set_overlays_dirty ();
4252 update_marker_labels ();
4258 Editor::queue_visual_change (framepos_t where)
4260 pending_visual_change.add (VisualChange::TimeOrigin);
4261 pending_visual_change.time_origin = where;
4262 ensure_visual_change_idle_handler ();
4266 Editor::queue_visual_change (double fpu)
4268 pending_visual_change.add (VisualChange::ZoomLevel);
4269 pending_visual_change.frames_per_unit = fpu;
4271 ensure_visual_change_idle_handler ();
4275 Editor::queue_visual_change_y (double y)
4277 pending_visual_change.add (VisualChange::YOrigin);
4278 pending_visual_change.y_origin = y;
4280 ensure_visual_change_idle_handler ();
4284 Editor::ensure_visual_change_idle_handler ()
4286 if (pending_visual_change.idle_handler_id < 0) {
4287 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4292 Editor::_idle_visual_changer (void* arg)
4294 return static_cast<Editor*>(arg)->idle_visual_changer ();
4298 Editor::idle_visual_changer ()
4300 VisualChange::Type p = pending_visual_change.pending;
4301 pending_visual_change.pending = (VisualChange::Type) 0;
4303 double const last_time_origin = horizontal_position ();
4305 if (p & VisualChange::TimeOrigin) {
4306 /* This is a bit of a hack, but set_frames_per_unit
4307 below will (if called) end up with the
4308 CrossfadeViews looking at Editor::leftmost_frame,
4309 and if we're changing origin and zoom in the same
4310 operation it will be the wrong value unless we
4314 leftmost_frame = pending_visual_change.time_origin;
4317 if (p & VisualChange::ZoomLevel) {
4318 set_frames_per_unit (pending_visual_change.frames_per_unit);
4320 compute_fixed_ruler_scale ();
4321 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4322 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4323 update_tempo_based_rulers ();
4325 if (p & VisualChange::TimeOrigin) {
4326 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4328 if (p & VisualChange::YOrigin) {
4329 vertical_adjustment.set_value (pending_visual_change.y_origin);
4332 if (last_time_origin == horizontal_position ()) {
4333 /* changed signal not emitted */
4334 update_fixed_rulers ();
4335 redisplay_tempo (true);
4338 _summary->set_overlays_dirty ();
4340 pending_visual_change.idle_handler_id = -1;
4341 return 0; /* this is always a one-shot call */
4344 struct EditorOrderTimeAxisSorter {
4345 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4346 return a->order () < b->order ();
4351 Editor::sort_track_selection (TrackViewList* sel)
4353 EditorOrderTimeAxisSorter cmp;
4358 selection->tracks.sort (cmp);
4363 Editor::get_preferred_edit_position (bool ignore_playhead)
4366 framepos_t where = 0;
4367 EditPoint ep = _edit_point;
4369 if (entered_marker) {
4370 return entered_marker->position();
4373 if (ignore_playhead && ep == EditAtPlayhead) {
4374 ep = EditAtSelectedMarker;
4378 case EditAtPlayhead:
4379 where = _session->audible_frame();
4382 case EditAtSelectedMarker:
4383 if (!selection->markers.empty()) {
4385 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4388 where = loc->start();
4399 if (!mouse_frame (where, ignored)) {
4400 /* XXX not right but what can we do ? */
4411 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4413 if (!_session) return;
4415 begin_reversible_command (cmd);
4419 if ((tll = transport_loop_location()) == 0) {
4420 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4421 XMLNode &before = _session->locations()->get_state();
4422 _session->locations()->add (loc, true);
4423 _session->set_auto_loop_location (loc);
4424 XMLNode &after = _session->locations()->get_state();
4425 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4427 XMLNode &before = tll->get_state();
4428 tll->set_hidden (false, this);
4429 tll->set (start, end);
4430 XMLNode &after = tll->get_state();
4431 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4434 commit_reversible_command ();
4438 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4440 if (!_session) return;
4442 begin_reversible_command (cmd);
4446 if ((tpl = transport_punch_location()) == 0) {
4447 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4448 XMLNode &before = _session->locations()->get_state();
4449 _session->locations()->add (loc, true);
4450 _session->set_auto_loop_location (loc);
4451 XMLNode &after = _session->locations()->get_state();
4452 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4455 XMLNode &before = tpl->get_state();
4456 tpl->set_hidden (false, this);
4457 tpl->set (start, end);
4458 XMLNode &after = tpl->get_state();
4459 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4462 commit_reversible_command ();
4465 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4466 * @param rs List to which found regions are added.
4467 * @param where Time to look at.
4468 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4471 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4473 const TrackViewList* tracks;
4476 tracks = &track_views;
4481 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4484 boost::shared_ptr<Track> tr;
4485 boost::shared_ptr<Playlist> pl;
4487 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4489 Playlist::RegionList* regions = pl->regions_at (
4490 (framepos_t) floor ( (double)where * tr->speed()));
4492 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4493 RegionView* rv = rtv->view()->find_view (*i);
4506 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4508 const TrackViewList* tracks;
4511 tracks = &track_views;
4516 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4517 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4519 boost::shared_ptr<Track> tr;
4520 boost::shared_ptr<Playlist> pl;
4522 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4524 Playlist::RegionList* regions = pl->regions_touched (
4525 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4527 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4529 RegionView* rv = rtv->view()->find_view (*i);
4542 /** Get regions using the following conditions:
4543 * 1. If the edit point is `mouse':
4544 * if the mouse is over a selected region, or no region, return all selected regions.
4545 * if the mouse is over an unselected region, return just that region.
4546 * 2. For all other edit points:
4547 * return the selected regions AND those that are both under the edit position
4548 * AND on a selected track, or on a track which is in the same active edit-enabled route group
4549 * as a selected region.
4551 * The rationale here is that the mouse edit point is special in that its position describes
4552 * both a time and a track; the other edit modes only describe a time.
4554 * @param rs Returned region list.
4558 Editor::get_regions_from_selection_and_edit_point ()
4560 if (_edit_point == EditAtMouse) {
4561 if (entered_regionview == 0 || selection->regions.contains (entered_regionview)) {
4562 return selection->regions;
4565 rs.add (entered_regionview);
4570 /* We're using the edit point, but its not EditAtMouse */
4572 /* Start with selected regions */
4573 RegionSelection rs = selection->regions;
4575 TrackViewList tracks = selection->tracks;
4577 /* Tracks is currently the set of selected tracks; add any other tracks that
4578 have regions that are in the same edit-activated route group as one of
4581 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4583 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4584 if (g && g->is_active() && g->is_edit()) {
4585 tracks.add (axis_views_from_routes (g->route_list()));
4590 if (!tracks.empty()) {
4591 /* now find regions that are at the edit position on those tracks */
4592 framepos_t const where = get_preferred_edit_position ();
4593 get_regions_at (rs, where, tracks);
4601 Editor::get_regions_from_selection_and_entered ()
4603 RegionSelection rs = selection->regions;
4605 if (rs.empty() && entered_regionview) {
4606 rs.add (entered_regionview);
4613 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4615 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4617 RouteTimeAxisView* tatv;
4619 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4621 boost::shared_ptr<Playlist> pl;
4622 vector<boost::shared_ptr<Region> > results;
4624 boost::shared_ptr<Track> tr;
4626 if ((tr = tatv->track()) == 0) {
4631 if ((pl = (tr->playlist())) != 0) {
4632 pl->get_region_list_equivalent_regions (region, results);
4635 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4636 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4637 regions.push_back (marv);
4646 Editor::show_rhythm_ferret ()
4648 if (rhythm_ferret == 0) {
4649 rhythm_ferret = new RhythmFerret(*this);
4652 rhythm_ferret->set_session (_session);
4653 rhythm_ferret->show ();
4654 rhythm_ferret->present ();
4658 Editor::first_idle ()
4660 MessageDialog* dialog = 0;
4662 if (track_views.size() > 1) {
4663 dialog = new MessageDialog (*this,
4664 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4669 ARDOUR_UI::instance()->flush_pending ();
4672 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4676 // first idle adds route children (automation tracks), so we need to redisplay here
4677 _routes->redisplay ();
4685 Editor::_idle_resize (gpointer arg)
4687 return ((Editor*)arg)->idle_resize ();
4691 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4693 if (resize_idle_id < 0) {
4694 resize_idle_id = g_idle_add (_idle_resize, this);
4695 _pending_resize_amount = 0;
4698 /* make a note of the smallest resulting height, so that we can clamp the
4699 lower limit at TimeAxisView::hSmall */
4701 int32_t min_resulting = INT32_MAX;
4703 _pending_resize_amount += h;
4704 _pending_resize_view = view;
4706 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4708 if (selection->tracks.contains (_pending_resize_view)) {
4709 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4710 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4714 if (min_resulting < 0) {
4719 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4720 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4724 /** Handle pending resizing of tracks */
4726 Editor::idle_resize ()
4728 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4730 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4731 selection->tracks.contains (_pending_resize_view)) {
4733 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4734 if (*i != _pending_resize_view) {
4735 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4740 _pending_resize_amount = 0;
4742 _group_tabs->set_dirty ();
4743 resize_idle_id = -1;
4751 ENSURE_GUI_THREAD (*this, &Editor::located);
4753 playhead_cursor->set_position (_session->audible_frame ());
4754 if (_follow_playhead && !_pending_initial_locate) {
4755 reset_x_origin_to_follow_playhead ();
4758 _pending_locate_request = false;
4759 _pending_initial_locate = false;
4763 Editor::region_view_added (RegionView *)
4765 _summary->set_dirty ();
4769 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4771 TrackViewList::const_iterator j = track_views.begin ();
4772 while (j != track_views.end()) {
4773 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4774 if (rtv && rtv->route() == r) {
4785 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4789 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4790 TimeAxisView* tv = axis_view_from_route (*i);
4801 Editor::handle_new_route (RouteList& routes)
4803 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4805 RouteTimeAxisView *rtv;
4806 list<RouteTimeAxisView*> new_views;
4808 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4809 boost::shared_ptr<Route> route = (*x);
4811 if (route->is_hidden() || route->is_monitor()) {
4815 DataType dt = route->input()->default_type();
4817 if (dt == ARDOUR::DataType::AUDIO) {
4818 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4819 } else if (dt == ARDOUR::DataType::MIDI) {
4820 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4822 throw unknown_type();
4825 new_views.push_back (rtv);
4826 track_views.push_back (rtv);
4828 rtv->effective_gain_display ();
4830 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4833 _routes->routes_added (new_views);
4835 if (show_editor_mixer_when_tracks_arrive) {
4836 show_editor_mixer (true);
4839 editor_list_button.set_sensitive (true);
4841 _summary->set_dirty ();
4845 Editor::timeaxisview_deleted (TimeAxisView *tv)
4847 if (_session && _session->deletion_in_progress()) {
4848 /* the situation is under control */
4852 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4854 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4856 _routes->route_removed (tv);
4858 if (tv == entered_track) {
4862 TimeAxisView::Children c = tv->get_child_list ();
4863 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4864 if (entered_track == i->get()) {
4869 /* remove it from the list of track views */
4871 TrackViewList::iterator i;
4873 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4874 i = track_views.erase (i);
4877 /* update whatever the current mixer strip is displaying, if revelant */
4879 boost::shared_ptr<Route> route;
4882 route = rtav->route ();
4885 if (current_mixer_strip && current_mixer_strip->route() == route) {
4887 TimeAxisView* next_tv;
4889 if (track_views.empty()) {
4891 } else if (i == track_views.end()) {
4892 next_tv = track_views.front();
4899 set_selected_mixer_strip (*next_tv);
4901 /* make the editor mixer strip go away setting the
4902 * button to inactive (which also unticks the menu option)
4905 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4911 Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/)
4913 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4915 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4916 // this will hide the mixer strip
4917 set_selected_mixer_strip (*tv);
4920 _routes->hide_track_in_display (*tv);
4924 Editor::sync_track_view_list_and_routes ()
4926 track_views = TrackViewList (_routes->views ());
4928 _summary->set_dirty ();
4929 _group_tabs->set_dirty ();
4931 return false; // do not call again (until needed)
4935 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4937 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4942 /** Find a RouteTimeAxisView by the ID of its route */
4944 Editor::get_route_view_by_route_id (PBD::ID& id) const
4946 RouteTimeAxisView* v;
4948 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4949 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4950 if(v->route()->id() == id) {
4960 Editor::fit_route_group (RouteGroup *g)
4962 TrackViewList ts = axis_views_from_routes (g->route_list ());
4967 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4969 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4972 _session->cancel_audition ();
4976 if (_session->is_auditioning()) {
4977 _session->cancel_audition ();
4978 if (r == last_audition_region) {
4983 _session->audition_region (r);
4984 last_audition_region = r;
4989 Editor::hide_a_region (boost::shared_ptr<Region> r)
4991 r->set_hidden (true);
4995 Editor::show_a_region (boost::shared_ptr<Region> r)
4997 r->set_hidden (false);
5001 Editor::audition_region_from_region_list ()
5003 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5007 Editor::hide_region_from_region_list ()
5009 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5013 Editor::show_region_in_region_list ()
5015 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5019 Editor::step_edit_status_change (bool yn)
5022 start_step_editing ();
5024 stop_step_editing ();
5029 Editor::start_step_editing ()
5031 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5035 Editor::stop_step_editing ()
5037 step_edit_connection.disconnect ();
5041 Editor::check_step_edit ()
5043 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5044 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5046 mtv->check_step_edit ();
5050 return true; // do it again, till we stop
5054 Editor::horizontal_scroll_left_press ()
5056 ++_scroll_callbacks;
5058 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5059 /* delay the first auto-repeat */
5063 double x = leftmost_position() - current_page_frames() / 5;
5070 /* do hacky auto-repeat */
5071 if (!_scroll_connection.connected ()) {
5072 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
5073 _scroll_callbacks = 0;
5080 Editor::horizontal_scroll_left_release ()
5082 _scroll_connection.disconnect ();
5086 Editor::horizontal_scroll_right_press ()
5088 ++_scroll_callbacks;
5090 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5091 /* delay the first auto-repeat */
5095 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5097 /* do hacky auto-repeat */
5098 if (!_scroll_connection.connected ()) {
5099 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
5100 _scroll_callbacks = 0;
5107 Editor::horizontal_scroll_right_release ()
5109 _scroll_connection.disconnect ();
5112 /** Queue a change for the Editor viewport x origin to follow the playhead */
5114 Editor::reset_x_origin_to_follow_playhead ()
5116 framepos_t const frame = playhead_cursor->current_frame;
5118 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5120 if (_session->transport_speed() < 0) {
5122 if (frame > (current_page_frames() / 2)) {
5123 center_screen (frame-(current_page_frames()/2));
5125 center_screen (current_page_frames()/2);
5130 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 3/4 of the way along the page */
5138 l = frame - (3 * current_page_frames() / 4);
5145 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5148 if (_session->transport_rolling()) {
5149 /* rolling: end up with the playhead on the left of the page */
5150 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5152 /* not rolling: end up with the playhead 1/4 of the way along the page */
5153 center_screen_internal (frame + (current_page_frames() / 4), 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) {
5209 reset_x_origin_to_follow_playhead ();
5214 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5218 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5219 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5220 if (target <= 0.0) {
5223 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5224 target = (target * 0.15) + (current * 0.85);
5230 set_horizontal_position (current);
5239 Editor::session_going_away ()
5241 _have_idled = false;
5243 _session_connections.drop_connections ();
5245 super_rapid_screen_update_connection.disconnect ();
5247 selection->clear ();
5248 cut_buffer->clear ();
5250 clicked_regionview = 0;
5251 clicked_axisview = 0;
5252 clicked_routeview = 0;
5253 clicked_crossfadeview = 0;
5254 entered_regionview = 0;
5256 last_update_frame = 0;
5259 playhead_cursor->canvas_item.hide ();
5261 /* rip everything out of the list displays */
5265 _route_groups->clear ();
5267 /* do this first so that deleting a track doesn't reset cms to null
5268 and thus cause a leak.
5271 if (current_mixer_strip) {
5272 if (current_mixer_strip->get_parent() != 0) {
5273 global_hpacker.remove (*current_mixer_strip);
5275 delete current_mixer_strip;
5276 current_mixer_strip = 0;
5279 /* delete all trackviews */
5281 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5284 track_views.clear ();
5286 zoom_range_clock.set_session (0);
5287 nudge_clock.set_session (0);
5289 editor_list_button.set_active(false);
5290 editor_list_button.set_sensitive(false);
5292 /* clear tempo/meter rulers */
5293 remove_metric_marks ();
5295 clear_marker_display ();
5297 delete current_bbt_points;
5298 current_bbt_points = 0;
5300 /* get rid of any existing editor mixer strip */
5302 WindowTitle title(Glib::get_application_name());
5303 title += _("Editor");
5305 set_title (title.get_string());
5307 SessionHandlePtr::session_going_away ();
5312 Editor::show_editor_list (bool yn)
5315 the_notebook.show();
5317 the_notebook.hide();
5322 Editor::change_region_layering_order ()
5324 framepos_t const position = get_preferred_edit_position ();
5326 if (!clicked_routeview) {
5327 if (layering_order_editor) {
5328 layering_order_editor->hide ();
5333 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5339 boost::shared_ptr<Playlist> pl = track->playlist();
5345 if (layering_order_editor == 0) {
5346 layering_order_editor = new RegionLayeringOrderEditor(*this);
5349 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5350 layering_order_editor->maybe_present ();
5354 Editor::update_region_layering_order_editor ()
5356 if (layering_order_editor && layering_order_editor->is_visible ()) {
5357 change_region_layering_order ();
5362 Editor::setup_fade_images ()
5364 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5365 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5366 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5367 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5368 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5370 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5371 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5372 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5373 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5374 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5378 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5380 Editor::action_menu_item (std::string const & name)
5382 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5385 return *manage (a->create_menu_item ());