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"
122 #include "imageframe_socket_handler.h"
126 using namespace ARDOUR;
129 using namespace Glib;
130 using namespace Gtkmm2ext;
131 using namespace Editing;
133 using PBD::internationalize;
135 using Gtkmm2ext::Keyboard;
137 const double Editor::timebar_height = 15.0;
139 #include "editor_xpms"
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"),
210 /* Soundfile drag-n-drop */
212 Gdk::Cursor* Editor::cross_hair_cursor = 0;
213 Gdk::Cursor* Editor::selector_cursor = 0;
214 Gdk::Cursor* Editor::trimmer_cursor = 0;
215 Gdk::Cursor* Editor::left_side_trim_cursor = 0;
216 Gdk::Cursor* Editor::right_side_trim_cursor = 0;
217 Gdk::Cursor* Editor::fade_in_cursor = 0;
218 Gdk::Cursor* Editor::fade_out_cursor = 0;
219 Gdk::Cursor* Editor::grabber_cursor = 0;
220 Gdk::Cursor* Editor::grabber_note_cursor = 0;
221 Gdk::Cursor* Editor::grabber_edit_point_cursor = 0;
222 Gdk::Cursor* Editor::zoom_in_cursor = 0;
223 Gdk::Cursor* Editor::zoom_out_cursor = 0;
224 Gdk::Cursor* Editor::time_fx_cursor = 0;
225 Gdk::Cursor* Editor::fader_cursor = 0;
226 Gdk::Cursor* Editor::speaker_cursor = 0;
227 Gdk::Cursor* Editor::midi_pencil_cursor = 0;
228 Gdk::Cursor* Editor::midi_select_cursor = 0;
229 Gdk::Cursor* Editor::midi_resize_cursor = 0;
230 Gdk::Cursor* Editor::midi_erase_cursor = 0;
231 Gdk::Cursor* Editor::wait_cursor = 0;
232 Gdk::Cursor* Editor::timebar_cursor = 0;
233 Gdk::Cursor* Editor::transparent_cursor = 0;
234 Gdk::Cursor* Editor::up_down_cursor = 0;
237 show_me_the_size (Requisition* r, const char* what)
239 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
244 pane_size_watcher (Paned* pane)
246 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
247 it is no longer accessible. so stop that. this doesn't happen on X11,
248 just the quartz backend.
253 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
255 gint pos = pane->get_position ();
257 if (pos > max_width_of_lhs) {
258 pane->set_position (max_width_of_lhs);
264 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
266 /* time display buttons */
267 , minsec_label (_("Mins:Secs"))
268 , bbt_label (_("Bars:Beats"))
269 , timecode_label (_("Timecode"))
270 , frame_label (_("Samples"))
271 , tempo_label (_("Tempo"))
272 , meter_label (_("Meter"))
273 , mark_label (_("Location Markers"))
274 , range_mark_label (_("Range Markers"))
275 , transport_mark_label (_("Loop/Punch Ranges"))
276 , cd_mark_label (_("CD Markers"))
277 , edit_packer (4, 4, true)
279 /* the values here don't matter: layout widgets
280 reset them as needed.
283 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
285 /* tool bar related */
287 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
289 , toolbar_selection_clock_table (2,3)
291 , automation_mode_button (_("mode"))
292 , global_automation_button (_("automation"))
294 , midi_panic_button (_("Panic"))
297 , image_socket_listener(0)
302 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
303 , meters_running(false)
304 , _pending_locate_request (false)
305 , _pending_initial_locate (false)
306 , _last_cut_copy_source_track (0)
308 , _region_selection_change_updates_region_list (true)
312 /* we are a singleton */
314 PublicEditor::_instance = this;
318 selection = new Selection (this);
319 cut_buffer = new Selection (this);
321 clicked_regionview = 0;
322 clicked_axisview = 0;
323 clicked_routeview = 0;
324 clicked_crossfadeview = 0;
325 clicked_control_point = 0;
326 last_update_frame = 0;
327 pre_press_cursor = 0;
328 _drags = new DragManager (this);
329 current_mixer_strip = 0;
330 current_bbt_points = 0;
333 snap_type_strings = I18N (_snap_type_strings);
334 snap_mode_strings = I18N (_snap_mode_strings);
335 zoom_focus_strings = I18N (_zoom_focus_strings);
336 edit_point_strings = I18N (_edit_point_strings);
337 #ifdef USE_RUBBERBAND
338 rb_opt_strings = I18N (_rb_opt_strings);
342 snap_threshold = 5.0;
343 bbt_beat_subdivision = 4;
346 last_autoscroll_x = 0;
347 last_autoscroll_y = 0;
348 autoscroll_active = false;
349 autoscroll_timeout_tag = -1;
354 current_interthread_info = 0;
355 _show_measures = true;
356 show_gain_after_trim = false;
357 verbose_cursor_on = true;
358 last_item_entered = 0;
360 have_pending_keyboard_selection = false;
361 _follow_playhead = true;
362 _stationary_playhead = false;
363 _xfade_visibility = true;
364 editor_ruler_menu = 0;
365 no_ruler_shown_update = false;
367 session_range_marker_menu = 0;
368 range_marker_menu = 0;
369 marker_menu_item = 0;
370 tempo_or_meter_marker_menu = 0;
371 transport_marker_menu = 0;
372 new_transport_marker_menu = 0;
373 editor_mixer_strip_width = Wide;
374 show_editor_mixer_when_tracks_arrive = false;
375 region_edit_menu_split_multichannel_item = 0;
376 region_edit_menu_split_item = 0;
379 current_stepping_trackview = 0;
381 entered_regionview = 0;
383 clear_entered_track = false;
386 button_release_can_deselect = true;
387 _dragging_playhead = false;
388 _dragging_edit_point = false;
389 select_new_marker = false;
391 layering_order_editor = 0;
393 no_save_visual = false;
396 scrubbing_direction = 0;
400 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
401 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
402 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
403 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
404 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
406 _edit_point = EditAtMouse;
407 _internal_editing = false;
408 current_canvas_cursor = 0;
410 frames_per_unit = 2048; /* too early to use reset_zoom () */
412 _scroll_callbacks = 0;
414 zoom_focus = ZoomFocusLeft;
415 set_zoom_focus (ZoomFocusLeft);
416 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
418 bbt_label.set_name ("EditorTimeButton");
419 bbt_label.set_size_request (-1, (int)timebar_height);
420 bbt_label.set_alignment (1.0, 0.5);
421 bbt_label.set_padding (5,0);
423 bbt_label.set_no_show_all();
424 minsec_label.set_name ("EditorTimeButton");
425 minsec_label.set_size_request (-1, (int)timebar_height);
426 minsec_label.set_alignment (1.0, 0.5);
427 minsec_label.set_padding (5,0);
428 minsec_label.hide ();
429 minsec_label.set_no_show_all();
430 timecode_label.set_name ("EditorTimeButton");
431 timecode_label.set_size_request (-1, (int)timebar_height);
432 timecode_label.set_alignment (1.0, 0.5);
433 timecode_label.set_padding (5,0);
434 timecode_label.hide ();
435 timecode_label.set_no_show_all();
436 frame_label.set_name ("EditorTimeButton");
437 frame_label.set_size_request (-1, (int)timebar_height);
438 frame_label.set_alignment (1.0, 0.5);
439 frame_label.set_padding (5,0);
441 frame_label.set_no_show_all();
443 tempo_label.set_name ("EditorTimeButton");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
448 tempo_label.set_no_show_all();
449 meter_label.set_name ("EditorTimeButton");
450 meter_label.set_size_request (-1, (int)timebar_height);
451 meter_label.set_alignment (1.0, 0.5);
452 meter_label.set_padding (5,0);
454 meter_label.set_no_show_all();
455 mark_label.set_name ("EditorTimeButton");
456 mark_label.set_size_request (-1, (int)timebar_height);
457 mark_label.set_alignment (1.0, 0.5);
458 mark_label.set_padding (5,0);
460 mark_label.set_no_show_all();
461 cd_mark_label.set_name ("EditorTimeButton");
462 cd_mark_label.set_size_request (-1, (int)timebar_height);
463 cd_mark_label.set_alignment (1.0, 0.5);
464 cd_mark_label.set_padding (5,0);
465 cd_mark_label.hide();
466 cd_mark_label.set_no_show_all();
467 range_mark_label.set_name ("EditorTimeButton");
468 range_mark_label.set_size_request (-1, (int)timebar_height);
469 range_mark_label.set_alignment (1.0, 0.5);
470 range_mark_label.set_padding (5,0);
471 range_mark_label.hide();
472 range_mark_label.set_no_show_all();
473 transport_mark_label.set_name ("EditorTimeButton");
474 transport_mark_label.set_size_request (-1, (int)timebar_height);
475 transport_mark_label.set_alignment (1.0, 0.5);
476 transport_mark_label.set_padding (5,0);
477 transport_mark_label.hide();
478 transport_mark_label.set_no_show_all();
480 initialize_rulers ();
481 initialize_canvas ();
482 _summary = new EditorSummary (this);
484 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
485 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
486 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
487 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
488 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
490 edit_controls_vbox.set_spacing (0);
491 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
492 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
494 HBox* h = manage (new HBox);
495 _group_tabs = new EditorGroupTabs (this);
496 h->pack_start (*_group_tabs, PACK_SHRINK);
497 h->pack_start (edit_controls_vbox);
498 controls_layout.add (*h);
500 controls_layout.set_name ("EditControlsBase");
501 controls_layout.add_events (Gdk::SCROLL_MASK);
502 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
504 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
505 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
506 controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request));
510 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
511 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
512 0.0, 1.0, 100.0, 1.0));
513 pad_line_1->property_color_rgba() = 0xFF0000FF;
517 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
518 time_canvas_vbox.set_size_request (-1, -1);
520 ruler_label_event_box.add (ruler_label_vbox);
521 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
522 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
524 time_button_event_box.add (time_button_vbox);
525 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
526 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
528 /* these enable us to have a dedicated window (for cursor setting, etc.)
529 for the canvas areas.
532 track_canvas_event_box.add (*track_canvas);
534 time_canvas_event_box.add (time_canvas_vbox);
535 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
537 edit_packer.set_col_spacings (0);
538 edit_packer.set_row_spacings (0);
539 edit_packer.set_homogeneous (false);
540 edit_packer.set_border_width (0);
541 edit_packer.set_name ("EditorWindow");
543 /* labels for the rulers */
544 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
545 /* labels for the marker "tracks" */
546 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
548 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
550 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
552 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
554 bottom_hbox.set_border_width (2);
555 bottom_hbox.set_spacing (3);
557 _route_groups = new EditorRouteGroups (this);
558 _routes = new EditorRoutes (this);
559 _regions = new EditorRegions (this);
560 _snapshots = new EditorSnapshots (this);
561 _locations = new EditorLocations (this);
565 nlabel = manage (new Label (_("Regions")));
566 nlabel->set_angle (-90);
567 the_notebook.append_page (_regions->widget (), *nlabel);
568 nlabel = manage (new Label (_("Tracks & Busses")));
569 nlabel->set_angle (-90);
570 the_notebook.append_page (_routes->widget (), *nlabel);
571 nlabel = manage (new Label (_("Snapshots")));
572 nlabel->set_angle (-90);
573 the_notebook.append_page (_snapshots->widget (), *nlabel);
574 nlabel = manage (new Label (_("Route Groups")));
575 nlabel->set_angle (-90);
576 the_notebook.append_page (_route_groups->widget (), *nlabel);
577 nlabel = manage (new Label (_("Ranges & Marks")));
578 nlabel->set_angle (-90);
579 the_notebook.append_page (_locations->widget (), *nlabel);
581 the_notebook.set_show_tabs (true);
582 the_notebook.set_scrollable (true);
583 the_notebook.popup_disable ();
584 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
585 the_notebook.show_all ();
587 post_maximal_editor_width = 0;
588 post_maximal_horizontal_pane_position = 0;
589 post_maximal_editor_height = 0;
590 post_maximal_vertical_pane_position = 0;
592 editor_summary_pane.pack1(edit_packer);
594 Button* summary_arrows_left_left = manage (new Button);
595 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
596 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
597 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
598 Button* summary_arrows_left_right = manage (new Button);
599 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
600 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
601 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
602 VBox* summary_arrows_left = manage (new VBox);
603 summary_arrows_left->pack_start (*summary_arrows_left_left);
604 summary_arrows_left->pack_start (*summary_arrows_left_right);
606 Button* summary_arrows_right_left = manage (new Button);
607 summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
608 summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
609 summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
610 Button* summary_arrows_right_right = manage (new Button);
611 summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
612 summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
613 summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
614 VBox* summary_arrows_right = manage (new VBox);
615 summary_arrows_right->pack_start (*summary_arrows_right_left);
616 summary_arrows_right->pack_start (*summary_arrows_right_right);
618 Frame* summary_frame = manage (new Frame);
619 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
620 summary_frame->add (*_summary);
621 summary_frame->show ();
623 _summary_hbox.pack_start (*summary_arrows_left, false, false);
624 _summary_hbox.pack_start (*summary_frame, true, true);
625 _summary_hbox.pack_start (*summary_arrows_right, false, false);
627 editor_summary_pane.pack2 (_summary_hbox);
629 edit_pane.pack1 (editor_summary_pane, true, true);
630 edit_pane.pack2 (the_notebook, false, true);
632 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
634 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
636 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
638 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
639 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
641 top_hbox.pack_start (toolbar_frame, false, true);
643 HBox *hbox = manage (new HBox);
644 hbox->pack_start (edit_pane, true, true);
646 global_vpacker.pack_start (top_hbox, false, false);
647 global_vpacker.pack_start (*hbox, true, true);
649 global_hpacker.pack_start (global_vpacker, true, true);
651 set_name ("EditorWindow");
652 add_accel_group (ActionManager::ui_manager->get_accel_group());
654 status_bar_hpacker.show ();
656 vpacker.pack_end (status_bar_hpacker, false, false);
657 vpacker.pack_end (global_hpacker, true, true);
659 /* register actions now so that set_state() can find them and set toggles/checks etc */
664 setup_midi_toolbar ();
666 _snap_type = SnapToBeat;
667 set_snap_to (_snap_type);
668 _snap_mode = SnapOff;
669 set_snap_mode (_snap_mode);
670 set_mouse_mode (MouseObject, true);
671 set_edit_point_preference (EditAtMouse, true);
673 _playlist_selector = new PlaylistSelector();
674 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
676 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
680 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
681 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
683 nudge_forward_button.set_name ("TransportButton");
684 nudge_backward_button.set_name ("TransportButton");
686 fade_context_menu.set_name ("ArdourContextMenu");
688 /* icons, titles, WM stuff */
690 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
691 Glib::RefPtr<Gdk::Pixbuf> icon;
693 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
694 window_icons.push_back (icon);
696 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
697 window_icons.push_back (icon);
699 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
700 window_icons.push_back (icon);
702 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
703 window_icons.push_back (icon);
705 if (!window_icons.empty()) {
706 set_icon_list (window_icons);
707 set_default_icon_list (window_icons);
710 WindowTitle title(Glib::get_application_name());
711 title += _("Editor");
712 set_title (title.get_string());
713 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
716 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
718 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
719 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
721 /* allow external control surfaces/protocols to do various things */
723 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
724 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
725 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
726 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
727 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
729 /* problematic: has to return a value and thus cannot be x-thread */
731 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
733 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
735 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
737 _ignore_region_action = false;
738 _last_region_menu_was_main = false;
739 _popup_region_menu_item = 0;
741 _show_marker_lines = false;
746 setup_fade_images ();
752 if(image_socket_listener) {
753 if(image_socket_listener->is_connected())
755 image_socket_listener->close_connection() ;
758 delete image_socket_listener ;
759 image_socket_listener = 0 ;
764 delete _route_groups;
770 Editor::add_toplevel_controls (Container& cont)
772 vpacker.pack_start (cont, false, false);
777 Editor::catch_vanishing_regionview (RegionView *rv)
779 /* note: the selection will take care of the vanishing
780 audioregionview by itself.
783 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
787 if (clicked_regionview == rv) {
788 clicked_regionview = 0;
791 if (entered_regionview == rv) {
792 set_entered_regionview (0);
795 if (!_all_region_actions_sensitized) {
796 sensitize_all_region_actions (true);
801 Editor::set_entered_regionview (RegionView* rv)
803 if (rv == entered_regionview) {
807 if (entered_regionview) {
808 entered_regionview->exited ();
811 if ((entered_regionview = rv) != 0) {
812 entered_regionview->entered (internal_editing ());
815 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
816 /* This RegionView entry might have changed what region actions
817 are allowed, so sensitize them all in case a key is pressed.
819 sensitize_all_region_actions (true);
824 Editor::set_entered_track (TimeAxisView* tav)
827 entered_track->exited ();
830 if ((entered_track = tav) != 0) {
831 entered_track->entered ();
836 Editor::show_window ()
838 if (! is_visible ()) {
841 /* re-hide editor list if necessary */
842 editor_list_button_toggled ();
844 /* re-hide summary widget if necessary */
845 parameter_changed ("show-summary");
847 parameter_changed ("show-edit-group-tabs");
849 /* now reset all audio_time_axis heights, because widgets might need
855 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
856 tv = (static_cast<TimeAxisView*>(*i));
865 Editor::instant_save ()
867 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
872 _session->add_instant_xml(get_state());
874 Config->add_instant_xml(get_state());
879 Editor::zoom_adjustment_changed ()
885 double fpu = zoom_range_clock.current_duration() / _canvas_width;
889 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
890 } else if (fpu > _session->current_end_frame() / _canvas_width) {
891 fpu = _session->current_end_frame() / _canvas_width;
892 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
899 Editor::control_scroll (float fraction)
901 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
907 double step = fraction * current_page_frames();
910 _control_scroll_target is an optional<T>
912 it acts like a pointer to an framepos_t, with
913 a operator conversion to boolean to check
914 that it has a value could possibly use
915 playhead_cursor->current_frame to store the
916 value and a boolean in the class to know
917 when it's out of date
920 if (!_control_scroll_target) {
921 _control_scroll_target = _session->transport_frame();
922 _dragging_playhead = true;
925 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
926 *_control_scroll_target = 0;
927 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
928 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
930 *_control_scroll_target += (framepos_t) floor (step);
933 /* move visuals, we'll catch up with it later */
935 playhead_cursor->set_position (*_control_scroll_target);
936 UpdateAllTransportClocks (*_control_scroll_target);
938 if (*_control_scroll_target > (current_page_frames() / 2)) {
939 /* try to center PH in window */
940 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
946 Now we do a timeout to actually bring the session to the right place
947 according to the playhead. This is to avoid reading disk buffers on every
948 call to control_scroll, which is driven by ScrollTimeline and therefore
949 probably by a control surface wheel which can generate lots of events.
951 /* cancel the existing timeout */
953 control_scroll_connection.disconnect ();
955 /* add the next timeout */
957 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
961 Editor::deferred_control_scroll (framepos_t /*target*/)
963 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
964 // reset for next stream
965 _control_scroll_target = boost::none;
966 _dragging_playhead = false;
971 Editor::access_action (std::string action_group, std::string action_item)
977 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
980 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
988 Editor::on_realize ()
990 Window::on_realize ();
995 Editor::map_position_change (framepos_t frame)
997 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1003 if (_follow_playhead) {
1004 center_screen (frame);
1007 playhead_cursor->set_position (frame);
1011 Editor::center_screen (framepos_t frame)
1013 double page = _canvas_width * frames_per_unit;
1015 /* if we're off the page, then scroll.
1018 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1019 center_screen_internal (frame, page);
1024 Editor::center_screen_internal (framepos_t frame, float page)
1029 frame -= (framepos_t) page;
1034 reset_x_origin (frame);
1039 Editor::update_title ()
1041 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1044 bool dirty = _session->dirty();
1046 string session_name;
1048 if (_session->snap_name() != _session->name()) {
1049 session_name = _session->snap_name();
1051 session_name = _session->name();
1055 session_name = "*" + session_name;
1058 WindowTitle title(session_name);
1059 title += Glib::get_application_name();
1060 set_title (title.get_string());
1065 Editor::set_session (Session *t)
1067 SessionHandlePtr::set_session (t);
1073 zoom_range_clock.set_session (_session);
1074 _playlist_selector->set_session (_session);
1075 nudge_clock.set_session (_session);
1076 _summary->set_session (_session);
1077 _group_tabs->set_session (_session);
1078 _route_groups->set_session (_session);
1079 _regions->set_session (_session);
1080 _snapshots->set_session (_session);
1081 _routes->set_session (_session);
1082 _locations->set_session (_session);
1084 if (rhythm_ferret) {
1085 rhythm_ferret->set_session (_session);
1088 if (analysis_window) {
1089 analysis_window->set_session (_session);
1093 sfbrowser->set_session (_session);
1096 compute_fixed_ruler_scale ();
1098 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1099 set_state (*node, Stateful::loading_state_version);
1101 /* catch up with the playhead */
1103 _session->request_locate (playhead_cursor->current_frame);
1104 _pending_initial_locate = true;
1108 /* These signals can all be emitted by a non-GUI thread. Therefore the
1109 handlers for them must not attempt to directly interact with the GUI,
1110 but use Gtkmm2ext::UI::instance()->call_slot();
1113 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1114 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1115 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1116 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1117 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1118 _session->TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_just_timecode, this), gui_context());
1119 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1120 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1121 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1122 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1123 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1124 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1125 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1126 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1127 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1129 if (Profile->get_sae()) {
1134 nframes_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1135 nudge_clock.set_mode(AudioClock::BBT);
1136 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1139 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1142 playhead_cursor->canvas_item.show ();
1144 Location* loc = _session->locations()->auto_loop_location();
1146 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1147 if (loc->start() == loc->end()) {
1148 loc->set_end (loc->start() + 1);
1150 _session->locations()->add (loc, false);
1151 _session->set_auto_loop_location (loc);
1154 loc->set_name (_("Loop"));
1157 loc = _session->locations()->auto_punch_location();
1159 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1160 if (loc->start() == loc->end()) {
1161 loc->set_end (loc->start() + 1);
1163 _session->locations()->add (loc, false);
1164 _session->set_auto_punch_location (loc);
1167 loc->set_name (_("Punch"));
1170 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1171 Config->map_parameters (pc);
1172 _session->config.map_parameters (pc);
1174 refresh_location_display ();
1176 restore_ruler_visibility ();
1177 //tempo_map_changed (PropertyChange (0));
1178 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1180 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1181 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1184 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1185 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1188 switch (_snap_type) {
1189 case SnapToRegionStart:
1190 case SnapToRegionEnd:
1191 case SnapToRegionSync:
1192 case SnapToRegionBoundary:
1193 build_region_boundary_cache ();
1200 /* register for undo history */
1201 _session->register_with_memento_command_factory(_id, this);
1203 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1205 start_updating_meters ();
1209 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1211 if (a->get_name() == "RegionMenu") {
1212 /* When the main menu's region menu is opened, we setup the actions so that they look right
1213 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1214 so we resensitize all region actions when the entered regionview or the region selection
1215 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1216 happens after the region context menu is opened. So we set a flag here, too.
1220 sensitize_the_right_region_actions ();
1221 _last_region_menu_was_main = true;
1226 Editor::build_cursors ()
1228 using namespace Gdk;
1231 Glib::RefPtr<Gdk::Pixbuf> zoom_in_cursor_pixbuf (::get_icon ("zoom_in_cursor"));
1232 zoom_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_in_cursor_pixbuf, 5, 5);
1236 Glib::RefPtr<Gdk::Pixbuf> zoom_out_cursor_pixbuf (::get_icon ("zoom_out_cursor"));
1237 zoom_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_out_cursor_pixbuf, 5, 5);
1240 Gdk::Color fbg ("#ffffff" );
1241 Gdk::Color ffg ("#000000" );
1244 RefPtr<Bitmap> source, mask;
1246 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1247 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1248 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1252 RefPtr<Bitmap> source, mask;
1253 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1254 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1255 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1259 RefPtr<Bitmap> bits;
1260 char pix[4] = { 0, 0, 0, 0 };
1261 bits = Bitmap::create (pix, 2, 2);
1263 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1267 RefPtr<Bitmap> bits;
1268 char pix[4] = { 0, 0, 0, 0 };
1269 bits = Bitmap::create (pix, 2, 2);
1271 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1275 Glib::RefPtr<Gdk::Pixbuf> grabber_pixbuf (::get_icon ("grabber"));
1276 grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0);
1280 Glib::RefPtr<Gdk::Pixbuf> grabber_note_pixbuf (::get_icon ("grabber_note"));
1281 grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10);
1285 Glib::RefPtr<Gdk::Pixbuf> grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point"));
1286 grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17);
1289 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1290 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1293 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_left_cursor"));
1294 left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11);
1298 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_right_cursor"));
1299 right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11);
1303 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_in_cursor"));
1304 fade_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 0, 40);
1308 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_out_cursor"));
1309 fade_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 27, 40);
1312 selector_cursor = new Gdk::Cursor (XTERM);
1313 time_fx_cursor = new Gdk::Cursor (SIZING);
1314 wait_cursor = new Gdk::Cursor (WATCH);
1315 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1316 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1317 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1318 midi_resize_cursor = new Gdk::Cursor (SIZING);
1319 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1320 up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW);
1323 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1325 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1327 using namespace Menu_Helpers;
1328 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1331 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1335 MenuList& items (fade_context_menu.items());
1339 switch (item_type) {
1341 case FadeInHandleItem:
1342 if (arv->audio_region()->fade_in_active()) {
1343 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1345 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1348 items.push_back (SeparatorElem());
1350 if (Profile->get_sae()) {
1352 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1353 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1360 *_fade_in_images[FadeLinear],
1361 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1365 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1370 *_fade_in_images[FadeFast],
1371 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1374 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1379 *_fade_in_images[FadeLogB],
1380 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1383 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1388 *_fade_in_images[FadeLogA],
1389 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1392 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1397 *_fade_in_images[FadeSlow],
1398 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1401 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1407 case FadeOutHandleItem:
1408 if (arv->audio_region()->fade_out_active()) {
1409 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1411 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1414 items.push_back (SeparatorElem());
1416 if (Profile->get_sae()) {
1417 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1418 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1424 *_fade_out_images[FadeLinear],
1425 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1429 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1434 *_fade_out_images[FadeFast],
1435 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1438 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1443 *_fade_out_images[FadeLogB],
1444 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1447 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1452 *_fade_out_images[FadeLogA],
1453 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1456 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1461 *_fade_out_images[FadeSlow],
1462 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1465 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471 fatal << _("programming error: ")
1472 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1477 fade_context_menu.popup (button, time);
1481 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection, framepos_t frame)
1483 using namespace Menu_Helpers;
1484 Menu* (Editor::*build_menu_function)(framepos_t);
1487 switch (item_type) {
1489 case RegionViewName:
1490 case RegionViewNameHighlight:
1491 case LeftFrameHandle:
1492 case RightFrameHandle:
1493 if (with_selection) {
1494 build_menu_function = &Editor::build_track_selection_context_menu;
1496 build_menu_function = &Editor::build_track_region_context_menu;
1501 if (with_selection) {
1502 build_menu_function = &Editor::build_track_selection_context_menu;
1504 build_menu_function = &Editor::build_track_context_menu;
1508 case CrossfadeViewItem:
1509 build_menu_function = &Editor::build_track_crossfade_context_menu;
1513 if (clicked_routeview->track()) {
1514 build_menu_function = &Editor::build_track_context_menu;
1516 build_menu_function = &Editor::build_track_bus_context_menu;
1521 /* probably shouldn't happen but if it does, we don't care */
1525 menu = (this->*build_menu_function)(frame);
1526 menu->set_name ("ArdourContextMenu");
1528 /* now handle specific situations */
1530 switch (item_type) {
1532 case RegionViewName:
1533 case RegionViewNameHighlight:
1534 case LeftFrameHandle:
1535 case RightFrameHandle:
1536 if (!with_selection) {
1537 if (region_edit_menu_split_item) {
1538 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1539 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1541 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1544 if (region_edit_menu_split_multichannel_item) {
1545 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1546 region_edit_menu_split_multichannel_item->set_sensitive (true);
1548 region_edit_menu_split_multichannel_item->set_sensitive (false);
1557 case CrossfadeViewItem:
1564 /* probably shouldn't happen but if it does, we don't care */
1568 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1570 /* Bounce to disk */
1572 using namespace Menu_Helpers;
1573 MenuList& edit_items = menu->items();
1575 edit_items.push_back (SeparatorElem());
1577 switch (clicked_routeview->audio_track()->freeze_state()) {
1578 case AudioTrack::NoFreeze:
1579 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1582 case AudioTrack::Frozen:
1583 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1586 case AudioTrack::UnFrozen:
1587 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1593 if (item_type == StreamItem && clicked_routeview) {
1594 clicked_routeview->build_underlay_menu(menu);
1597 /* When the region menu is opened, we setup the actions so that they look right
1600 sensitize_the_right_region_actions ();
1601 _last_region_menu_was_main = false;
1603 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1604 menu->popup (button, time);
1608 Editor::build_track_context_menu (framepos_t)
1610 using namespace Menu_Helpers;
1612 MenuList& edit_items = track_context_menu.items();
1615 add_dstream_context_items (edit_items);
1616 return &track_context_menu;
1620 Editor::build_track_bus_context_menu (framepos_t)
1622 using namespace Menu_Helpers;
1624 MenuList& edit_items = track_context_menu.items();
1627 add_bus_context_items (edit_items);
1628 return &track_context_menu;
1632 Editor::build_track_region_context_menu (framepos_t frame)
1634 using namespace Menu_Helpers;
1635 MenuList& edit_items = track_region_context_menu.items();
1638 /* we've just cleared the track region context menu, so the menu that these
1639 two items were on will have disappeared; stop them dangling.
1641 region_edit_menu_split_item = 0;
1642 region_edit_menu_split_multichannel_item = 0;
1644 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1647 boost::shared_ptr<Track> tr;
1648 boost::shared_ptr<Playlist> pl;
1650 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1651 mode and so offering region context is somewhat confusing.
1653 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1654 framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed());
1655 uint32_t regions_at = pl->count_regions_at (framepos);
1656 add_region_context_items (edit_items, regions_at > 1);
1660 add_dstream_context_items (edit_items);
1662 return &track_region_context_menu;
1666 Editor::build_track_crossfade_context_menu (framepos_t frame)
1668 using namespace Menu_Helpers;
1669 MenuList& edit_items = track_crossfade_context_menu.items();
1670 edit_items.clear ();
1672 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1675 boost::shared_ptr<Track> tr;
1676 boost::shared_ptr<Playlist> pl;
1677 boost::shared_ptr<AudioPlaylist> apl;
1679 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1681 AudioPlaylist::Crossfades xfades;
1683 apl->crossfades_at (frame, xfades);
1685 bool many = xfades.size() > 1;
1687 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1688 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1691 framepos_t framepos = (framepos_t) floor ((double)frame * tr->speed());
1692 uint32_t regions_at = pl->count_regions_at (framepos);
1693 add_region_context_items (edit_items, regions_at > 1);
1697 add_dstream_context_items (edit_items);
1699 return &track_crossfade_context_menu;
1703 Editor::analyze_region_selection ()
1705 if (analysis_window == 0) {
1706 analysis_window = new AnalysisWindow();
1709 analysis_window->set_session(_session);
1711 analysis_window->show_all();
1714 analysis_window->set_regionmode();
1715 analysis_window->analyze();
1717 analysis_window->present();
1721 Editor::analyze_range_selection()
1723 if (analysis_window == 0) {
1724 analysis_window = new AnalysisWindow();
1727 analysis_window->set_session(_session);
1729 analysis_window->show_all();
1732 analysis_window->set_rangemode();
1733 analysis_window->analyze();
1735 analysis_window->present();
1739 Editor::build_track_selection_context_menu (framepos_t)
1741 using namespace Menu_Helpers;
1742 MenuList& edit_items = track_selection_context_menu.items();
1743 edit_items.clear ();
1745 add_selection_context_items (edit_items);
1746 // edit_items.push_back (SeparatorElem());
1747 // add_dstream_context_items (edit_items);
1749 return &track_selection_context_menu;
1752 /** Add context menu items relevant to crossfades.
1753 * @param edit_items List to add the items to.
1756 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1758 using namespace Menu_Helpers;
1759 Menu *xfade_menu = manage (new Menu);
1760 MenuList& items = xfade_menu->items();
1761 xfade_menu->set_name ("ArdourContextMenu");
1764 if (xfade->active()) {
1770 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1771 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1773 if (xfade->can_follow_overlap()) {
1775 if (xfade->following_overlap()) {
1776 str = _("Convert to Short");
1778 str = _("Convert to Full");
1781 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1785 str = xfade->out()->name();
1787 str += xfade->in()->name();
1789 str = _("Crossfade");
1792 edit_items.push_back (MenuElem (str, *xfade_menu));
1793 edit_items.push_back (SeparatorElem());
1797 Editor::xfade_edit_left_region ()
1799 if (clicked_crossfadeview) {
1800 clicked_crossfadeview->left_view.show_region_editor ();
1805 Editor::xfade_edit_right_region ()
1807 if (clicked_crossfadeview) {
1808 clicked_crossfadeview->right_view.show_region_editor ();
1813 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1815 using namespace Menu_Helpers;
1817 /* OK, stick the region submenu at the top of the list, and then add
1821 /* we have to hack up the region name because "_" has a special
1822 meaning for menu titles.
1825 RegionSelection rs = get_regions_from_selection_and_entered ();
1827 string::size_type pos = 0;
1828 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1830 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1831 menu_item_name.replace (pos, 1, "__");
1835 if (_popup_region_menu_item == 0) {
1836 _popup_region_menu_item = new MenuItem (menu_item_name);
1837 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1838 _popup_region_menu_item->show ();
1840 _popup_region_menu_item->set_label (menu_item_name);
1843 edit_items.push_back (*_popup_region_menu_item);
1844 if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1845 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1847 edit_items.push_back (SeparatorElem());
1850 /** Add context menu items relevant to selection ranges.
1851 * @param edit_items List to add the items to.
1854 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1856 using namespace Menu_Helpers;
1858 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1859 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1861 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1864 if (!selection->regions.empty()) {
1865 edit_items.push_back (SeparatorElem());
1866 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)));
1867 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)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1872 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1879 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1884 edit_items.push_back (SeparatorElem());
1885 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1886 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1887 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1889 edit_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1891 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1892 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1893 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1894 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1899 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1901 using namespace Menu_Helpers;
1905 Menu *play_menu = manage (new Menu);
1906 MenuList& play_items = play_menu->items();
1907 play_menu->set_name ("ArdourContextMenu");
1909 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1910 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1911 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1912 play_items.push_back (SeparatorElem());
1913 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1915 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1919 Menu *select_menu = manage (new Menu);
1920 MenuList& select_items = select_menu->items();
1921 select_menu->set_name ("ArdourContextMenu");
1923 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1924 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1925 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1926 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1927 select_items.push_back (SeparatorElem());
1928 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1929 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1930 select_items.push_back (SeparatorElem());
1931 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1932 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1933 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1934 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1935 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1936 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1937 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1939 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1943 Menu *cutnpaste_menu = manage (new Menu);
1944 MenuList& cutnpaste_items = cutnpaste_menu->items();
1945 cutnpaste_menu->set_name ("ArdourContextMenu");
1947 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1948 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1949 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1951 cutnpaste_items.push_back (SeparatorElem());
1953 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1954 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1956 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1958 /* Adding new material */
1960 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1962 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1966 Menu *nudge_menu = manage (new Menu());
1967 MenuList& nudge_items = nudge_menu->items();
1968 nudge_menu->set_name ("ArdourContextMenu");
1970 edit_items.push_back (SeparatorElem());
1971 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1972 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1973 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1974 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1976 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1980 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1982 using namespace Menu_Helpers;
1986 Menu *play_menu = manage (new Menu);
1987 MenuList& play_items = play_menu->items();
1988 play_menu->set_name ("ArdourContextMenu");
1990 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1991 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1992 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1996 Menu *select_menu = manage (new Menu);
1997 MenuList& select_items = select_menu->items();
1998 select_menu->set_name ("ArdourContextMenu");
2000 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2001 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2002 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2003 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2004 select_items.push_back (SeparatorElem());
2005 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2006 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2007 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2008 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2010 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2014 Menu *cutnpaste_menu = manage (new Menu);
2015 MenuList& cutnpaste_items = cutnpaste_menu->items();
2016 cutnpaste_menu->set_name ("ArdourContextMenu");
2018 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2019 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2020 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2022 Menu *nudge_menu = manage (new Menu());
2023 MenuList& nudge_items = nudge_menu->items();
2024 nudge_menu->set_name ("ArdourContextMenu");
2026 edit_items.push_back (SeparatorElem());
2027 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2028 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2029 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2030 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2032 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2036 Editor::snap_type() const
2042 Editor::snap_mode() const
2048 Editor::set_snap_to (SnapType st)
2050 unsigned int snap_ind = (unsigned int)st;
2054 if (snap_ind > snap_type_strings.size() - 1) {
2056 _snap_type = (SnapType)snap_ind;
2059 string str = snap_type_strings[snap_ind];
2061 if (str != snap_type_selector.get_active_text()) {
2062 snap_type_selector.set_active_text (str);
2067 switch (_snap_type) {
2068 case SnapToBeatDiv32:
2069 case SnapToBeatDiv28:
2070 case SnapToBeatDiv24:
2071 case SnapToBeatDiv20:
2072 case SnapToBeatDiv16:
2073 case SnapToBeatDiv14:
2074 case SnapToBeatDiv12:
2075 case SnapToBeatDiv10:
2076 case SnapToBeatDiv8:
2077 case SnapToBeatDiv7:
2078 case SnapToBeatDiv6:
2079 case SnapToBeatDiv5:
2080 case SnapToBeatDiv4:
2081 case SnapToBeatDiv3:
2082 case SnapToBeatDiv2:
2083 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2084 update_tempo_based_rulers ();
2087 case SnapToRegionStart:
2088 case SnapToRegionEnd:
2089 case SnapToRegionSync:
2090 case SnapToRegionBoundary:
2091 build_region_boundary_cache ();
2099 SnapChanged (); /* EMIT SIGNAL */
2103 Editor::set_snap_mode (SnapMode mode)
2106 string str = snap_mode_strings[(int)mode];
2108 if (str != snap_mode_selector.get_active_text ()) {
2109 snap_mode_selector.set_active_text (str);
2115 Editor::set_edit_point_preference (EditPoint ep, bool force)
2117 bool changed = (_edit_point != ep);
2120 string str = edit_point_strings[(int)ep];
2122 if (str != edit_point_selector.get_active_text ()) {
2123 edit_point_selector.set_active_text (str);
2126 set_canvas_cursor ();
2128 if (!force && !changed) {
2132 const char* action=NULL;
2134 switch (_edit_point) {
2135 case EditAtPlayhead:
2136 action = "edit-at-playhead";
2138 case EditAtSelectedMarker:
2139 action = "edit-at-marker";
2142 action = "edit-at-mouse";
2146 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2148 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2152 bool in_track_canvas;
2154 if (!mouse_frame (foo, in_track_canvas)) {
2155 in_track_canvas = false;
2158 reset_canvas_action_sensitivity (in_track_canvas);
2164 Editor::set_state (const XMLNode& node, int /*version*/)
2166 const XMLProperty* prop;
2168 int x, y, xoff, yoff;
2171 if ((prop = node.property ("id")) != 0) {
2172 _id = prop->value ();
2175 g.base_width = default_width;
2176 g.base_height = default_height;
2182 if ((geometry = find_named_node (node, "geometry")) != 0) {
2186 if ((prop = geometry->property("x_size")) == 0) {
2187 prop = geometry->property ("x-size");
2190 g.base_width = atoi(prop->value());
2192 if ((prop = geometry->property("y_size")) == 0) {
2193 prop = geometry->property ("y-size");
2196 g.base_height = atoi(prop->value());
2199 if ((prop = geometry->property ("x_pos")) == 0) {
2200 prop = geometry->property ("x-pos");
2203 x = atoi (prop->value());
2206 if ((prop = geometry->property ("y_pos")) == 0) {
2207 prop = geometry->property ("y-pos");
2210 y = atoi (prop->value());
2213 if ((prop = geometry->property ("x_off")) == 0) {
2214 prop = geometry->property ("x-off");
2217 xoff = atoi (prop->value());
2219 if ((prop = geometry->property ("y_off")) == 0) {
2220 prop = geometry->property ("y-off");
2223 yoff = atoi (prop->value());
2227 set_default_size (g.base_width, g.base_height);
2230 if (_session && (prop = node.property ("playhead"))) {
2232 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2233 playhead_cursor->set_position (pos);
2235 playhead_cursor->set_position (0);
2238 if ((prop = node.property ("mixer-width"))) {
2239 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2242 if ((prop = node.property ("zoom-focus"))) {
2243 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2246 if ((prop = node.property ("zoom"))) {
2247 reset_zoom (PBD::atof (prop->value()));
2249 reset_zoom (frames_per_unit);
2252 if ((prop = node.property ("snap-to"))) {
2253 set_snap_to ((SnapType) atoi (prop->value()));
2256 if ((prop = node.property ("snap-mode"))) {
2257 set_snap_mode ((SnapMode) atoi (prop->value()));
2260 if ((prop = node.property ("mouse-mode"))) {
2261 MouseMode m = str2mousemode(prop->value());
2262 set_mouse_mode (m, true);
2264 set_mouse_mode (MouseObject, true);
2267 if ((prop = node.property ("left-frame")) != 0){
2269 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2270 reset_x_origin (pos);
2274 if ((prop = node.property ("y-origin")) != 0) {
2275 reset_y_origin (atof (prop->value ()));
2278 if ((prop = node.property ("internal-edit"))) {
2279 bool yn = string_is_affirmative (prop->value());
2280 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2282 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2283 tact->set_active (!yn);
2284 tact->set_active (yn);
2288 if ((prop = node.property ("join-object-range"))) {
2289 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2292 if ((prop = node.property ("edit-point"))) {
2293 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2296 if ((prop = node.property ("show-measures"))) {
2297 bool yn = string_is_affirmative (prop->value());
2298 _show_measures = yn;
2299 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2301 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2302 /* do it twice to force the change */
2303 tact->set_active (!yn);
2304 tact->set_active (yn);
2308 if ((prop = node.property ("follow-playhead"))) {
2309 bool yn = string_is_affirmative (prop->value());
2310 set_follow_playhead (yn);
2311 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 if (tact->get_active() != yn) {
2315 tact->set_active (yn);
2320 if ((prop = node.property ("stationary-playhead"))) {
2321 bool yn = (prop->value() == "yes");
2322 set_stationary_playhead (yn);
2323 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326 if (tact->get_active() != yn) {
2327 tact->set_active (yn);
2332 if ((prop = node.property ("region-list-sort-type"))) {
2333 RegionListSortType st;
2334 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2337 if ((prop = node.property ("xfades-visible"))) {
2338 bool yn = string_is_affirmative (prop->value());
2339 _xfade_visibility = !yn;
2340 // set_xfade_visibility (yn);
2343 if ((prop = node.property ("show-editor-mixer"))) {
2345 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2348 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2349 bool yn = string_is_affirmative (prop->value());
2351 /* do it twice to force the change */
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2357 if ((prop = node.property ("show-editor-list"))) {
2359 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2362 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363 bool yn = string_is_affirmative (prop->value());
2365 /* do it twice to force the change */
2367 tact->set_active (!yn);
2368 tact->set_active (yn);
2371 if ((prop = node.property (X_("editor-list-page")))) {
2372 the_notebook.set_current_page (atoi (prop->value ()));
2375 if ((prop = node.property (X_("show-marker-lines")))) {
2376 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2378 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2379 bool yn = string_is_affirmative (prop->value ());
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 XMLNodeList children = node.children ();
2386 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2387 selection->set_state (**i, Stateful::current_state_version);
2388 _regions->set_state (**i);
2395 Editor::get_state ()
2397 XMLNode* node = new XMLNode ("Editor");
2400 _id.print (buf, sizeof (buf));
2401 node->add_property ("id", buf);
2403 if (is_realized()) {
2404 Glib::RefPtr<Gdk::Window> win = get_window();
2406 int x, y, xoff, yoff, width, height;
2407 win->get_root_origin(x, y);
2408 win->get_position(xoff, yoff);
2409 win->get_size(width, height);
2411 XMLNode* geometry = new XMLNode ("geometry");
2413 snprintf(buf, sizeof(buf), "%d", width);
2414 geometry->add_property("x-size", string(buf));
2415 snprintf(buf, sizeof(buf), "%d", height);
2416 geometry->add_property("y-size", string(buf));
2417 snprintf(buf, sizeof(buf), "%d", x);
2418 geometry->add_property("x-pos", string(buf));
2419 snprintf(buf, sizeof(buf), "%d", y);
2420 geometry->add_property("y-pos", string(buf));
2421 snprintf(buf, sizeof(buf), "%d", xoff);
2422 geometry->add_property("x-off", string(buf));
2423 snprintf(buf, sizeof(buf), "%d", yoff);
2424 geometry->add_property("y-off", string(buf));
2425 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2426 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2427 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2428 geometry->add_property("edit-vertical-pane-pos", string(buf));
2430 node->add_child_nocopy (*geometry);
2433 maybe_add_mixer_strip_width (*node);
2435 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2436 node->add_property ("zoom-focus", buf);
2437 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2438 node->add_property ("zoom", buf);
2439 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2440 node->add_property ("snap-to", buf);
2441 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2442 node->add_property ("snap-mode", buf);
2444 node->add_property ("edit-point", enum_2_string (_edit_point));
2446 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2447 node->add_property ("playhead", buf);
2448 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2449 node->add_property ("left-frame", buf);
2450 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2451 node->add_property ("y-origin", buf);
2453 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2454 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2455 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2456 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2457 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2458 node->add_property ("mouse-mode", enum2str(mouse_mode));
2459 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2460 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2462 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2464 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2468 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2470 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2471 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2474 snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
2475 node->add_property (X_("editor-list-page"), buf);
2477 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2479 node->add_child_nocopy (selection->get_state ());
2480 node->add_child_nocopy (_regions->get_state ());
2487 /** @param y y offset from the top of all trackviews.
2488 * @return pair: TimeAxisView that y is over, layer index.
2489 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2490 * in stacked region display mode, otherwise 0.
2492 std::pair<TimeAxisView *, layer_t>
2493 Editor::trackview_by_y_position (double y)
2495 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2497 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2503 return std::make_pair ( (TimeAxisView *) 0, 0);
2506 /** Snap a position to the grid, if appropriate, taking into account current
2507 * grid settings and also the state of any snap modifier keys that may be pressed.
2508 * @param start Position to snap.
2509 * @param event Event to get current key modifier information from, or 0.
2512 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2514 if (!_session || !event) {
2518 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2519 if (_snap_mode == SnapOff) {
2520 snap_to_internal (start, direction, for_mark);
2523 if (_snap_mode != SnapOff) {
2524 snap_to_internal (start, direction, for_mark);
2530 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2532 if (!_session || _snap_mode == SnapOff) {
2536 snap_to_internal (start, direction, for_mark);
2540 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2542 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2543 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2545 switch (_snap_type) {
2546 case SnapToTimecodeFrame:
2547 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2548 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2550 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2554 case SnapToTimecodeSeconds:
2555 if (_session->timecode_offset_negative())
2557 start += _session->timecode_offset ();
2559 start -= _session->timecode_offset ();
2561 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2562 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2564 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2567 if (_session->timecode_offset_negative())
2569 start -= _session->timecode_offset ();
2571 start += _session->timecode_offset ();
2575 case SnapToTimecodeMinutes:
2576 if (_session->timecode_offset_negative())
2578 start += _session->timecode_offset ();
2580 start -= _session->timecode_offset ();
2582 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2583 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2585 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2587 if (_session->timecode_offset_negative())
2589 start -= _session->timecode_offset ();
2591 start += _session->timecode_offset ();
2595 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2601 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2603 const framepos_t one_second = _session->frame_rate();
2604 const framepos_t one_minute = _session->frame_rate() * 60;
2605 framepos_t presnap = start;
2609 switch (_snap_type) {
2610 case SnapToTimecodeFrame:
2611 case SnapToTimecodeSeconds:
2612 case SnapToTimecodeMinutes:
2613 return timecode_snap_to_internal (start, direction, for_mark);
2616 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2617 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2619 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2624 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2625 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2627 start = (framepos_t) floor ((double) start / one_second) * one_second;
2632 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2633 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2635 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2640 start = _session->tempo_map().round_to_bar (start, direction);
2644 start = _session->tempo_map().round_to_beat (start, direction);
2647 case SnapToBeatDiv32:
2648 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2650 case SnapToBeatDiv28:
2651 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2653 case SnapToBeatDiv24:
2654 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2656 case SnapToBeatDiv20:
2657 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2659 case SnapToBeatDiv16:
2660 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2662 case SnapToBeatDiv14:
2663 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2665 case SnapToBeatDiv12:
2666 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2668 case SnapToBeatDiv10:
2669 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2671 case SnapToBeatDiv8:
2672 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2674 case SnapToBeatDiv7:
2675 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2677 case SnapToBeatDiv6:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2680 case SnapToBeatDiv5:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2683 case SnapToBeatDiv4:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2686 case SnapToBeatDiv3:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2689 case SnapToBeatDiv2:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2698 _session->locations()->marks_either_side (start, before, after);
2700 if (before == max_framepos) {
2702 } else if (after == max_framepos) {
2704 } else if (before != max_framepos && after != max_framepos) {
2705 /* have before and after */
2706 if ((start - before) < (after - start)) {
2715 case SnapToRegionStart:
2716 case SnapToRegionEnd:
2717 case SnapToRegionSync:
2718 case SnapToRegionBoundary:
2719 if (!region_boundary_cache.empty()) {
2721 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2722 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2724 if (direction > 0) {
2725 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2727 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2730 if (next != region_boundary_cache.begin ()) {
2735 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2736 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2738 if (start > (p + n) / 2) {
2747 switch (_snap_mode) {
2753 if (presnap > start) {
2754 if (presnap > (start + unit_to_frame(snap_threshold))) {
2758 } else if (presnap < start) {
2759 if (presnap < (start - unit_to_frame(snap_threshold))) {
2765 /* handled at entry */
2773 Editor::setup_toolbar ()
2777 /* Mode Buttons (tool selection) */
2779 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2780 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2781 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2782 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2783 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2784 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2785 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2786 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2788 HBox* mode_box = manage(new HBox);
2789 mode_box->set_border_width (2);
2790 mode_box->set_spacing(4);
2792 /* table containing mode buttons */
2794 HBox* mouse_mode_button_box = manage (new HBox ());
2796 if (Profile->get_sae()) {
2797 mouse_mode_button_box->pack_start (mouse_move_button);
2799 mouse_mode_button_box->pack_start (mouse_move_button);
2800 mouse_mode_button_box->pack_start (join_object_range_button);
2801 mouse_mode_button_box->pack_start (mouse_select_button);
2804 mouse_mode_button_box->pack_start (mouse_zoom_button);
2806 if (!Profile->get_sae()) {
2807 mouse_mode_button_box->pack_start (mouse_gain_button);
2810 mouse_mode_button_box->pack_start (mouse_timefx_button);
2811 mouse_mode_button_box->pack_start (mouse_audition_button);
2812 mouse_mode_button_box->pack_start (internal_edit_button);
2814 vector<string> edit_mode_strings;
2815 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2816 if (!Profile->get_sae()) {
2817 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2819 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2821 edit_mode_selector.set_name ("EditModeSelector");
2822 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2823 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2825 mode_box->pack_start (edit_mode_selector);
2826 mode_box->pack_start (*mouse_mode_button_box);
2828 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2829 _mouse_mode_tearoff->set_name ("MouseModeBase");
2830 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2832 if (Profile->get_sae()) {
2833 _mouse_mode_tearoff->set_can_be_torn_off (false);
2836 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2837 &_mouse_mode_tearoff->tearoff_window()));
2838 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2839 &_mouse_mode_tearoff->tearoff_window(), 1));
2840 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2841 &_mouse_mode_tearoff->tearoff_window()));
2842 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2843 &_mouse_mode_tearoff->tearoff_window(), 1));
2845 mouse_move_button.set_mode (false);
2846 mouse_select_button.set_mode (false);
2847 mouse_gain_button.set_mode (false);
2848 mouse_zoom_button.set_mode (false);
2849 mouse_timefx_button.set_mode (false);
2850 mouse_audition_button.set_mode (false);
2851 join_object_range_button.set_mode (false);
2853 mouse_move_button.set_name ("MouseModeButton");
2854 mouse_select_button.set_name ("MouseModeButton");
2855 mouse_gain_button.set_name ("MouseModeButton");
2856 mouse_zoom_button.set_name ("MouseModeButton");
2857 mouse_timefx_button.set_name ("MouseModeButton");
2858 mouse_audition_button.set_name ("MouseModeButton");
2859 internal_edit_button.set_name ("MouseModeButton");
2860 join_object_range_button.set_name ("MouseModeButton");
2862 mouse_move_button.unset_flags (CAN_FOCUS);
2863 mouse_select_button.unset_flags (CAN_FOCUS);
2864 mouse_gain_button.unset_flags (CAN_FOCUS);
2865 mouse_zoom_button.unset_flags (CAN_FOCUS);
2866 mouse_timefx_button.unset_flags (CAN_FOCUS);
2867 mouse_audition_button.unset_flags (CAN_FOCUS);
2868 internal_edit_button.unset_flags (CAN_FOCUS);
2869 join_object_range_button.unset_flags (CAN_FOCUS);
2873 _zoom_box.set_spacing (1);
2874 _zoom_box.set_border_width (0);
2876 zoom_in_button.set_name ("EditorTimeButton");
2877 zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2878 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2880 zoom_out_button.set_name ("EditorTimeButton");
2881 zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2882 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2884 zoom_out_full_button.set_name ("EditorTimeButton");
2885 zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2886 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2888 zoom_focus_selector.set_name ("ZoomFocusSelector");
2889 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2890 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2892 _zoom_box.pack_start (zoom_out_button, false, false);
2893 _zoom_box.pack_start (zoom_in_button, false, false);
2894 _zoom_box.pack_start (zoom_out_full_button, false, false);
2896 _zoom_box.pack_start (zoom_focus_selector);
2898 /* Track zoom buttons */
2899 tav_expand_button.set_name ("TrackHeightButton");
2900 tav_expand_button.set_size_request(-1,20);
2901 tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2902 tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2904 tav_shrink_button.set_name ("TrackHeightButton");
2905 tav_shrink_button.set_size_request(-1,20);
2906 tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2907 tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2909 _zoom_box.pack_start (tav_shrink_button);
2910 _zoom_box.pack_start (tav_expand_button);
2912 _zoom_tearoff = manage (new TearOff (_zoom_box));
2914 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2915 &_zoom_tearoff->tearoff_window()));
2916 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2917 &_zoom_tearoff->tearoff_window(), 0));
2918 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2919 &_zoom_tearoff->tearoff_window()));
2920 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2921 &_zoom_tearoff->tearoff_window(), 0));
2923 snap_box.set_spacing (1);
2924 snap_box.set_border_width (2);
2926 snap_type_selector.set_name ("SnapTypeSelector");
2927 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2928 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2930 snap_mode_selector.set_name ("SnapModeSelector");
2931 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2932 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2934 edit_point_selector.set_name ("EditPointSelector");
2935 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2936 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2938 snap_box.pack_start (snap_mode_selector, false, false);
2939 snap_box.pack_start (snap_type_selector, false, false);
2940 snap_box.pack_start (edit_point_selector, false, false);
2944 HBox *nudge_box = manage (new HBox);
2945 nudge_box->set_spacing(1);
2946 nudge_box->set_border_width (2);
2948 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2949 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2951 nudge_box->pack_start (nudge_backward_button, false, false);
2952 nudge_box->pack_start (nudge_forward_button, false, false);
2953 nudge_box->pack_start (nudge_clock, false, false);
2956 /* Pack everything in... */
2958 HBox* hbox = manage (new HBox);
2959 hbox->set_spacing(10);
2961 _tools_tearoff = manage (new TearOff (*hbox));
2962 _tools_tearoff->set_name ("MouseModeBase");
2963 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2965 if (Profile->get_sae()) {
2966 _tools_tearoff->set_can_be_torn_off (false);
2969 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2970 &_tools_tearoff->tearoff_window()));
2971 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2972 &_tools_tearoff->tearoff_window(), 0));
2973 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2974 &_tools_tearoff->tearoff_window()));
2975 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2976 &_tools_tearoff->tearoff_window(), 0));
2978 toolbar_hbox.set_spacing (10);
2979 toolbar_hbox.set_border_width (1);
2981 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2982 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2983 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2985 hbox->pack_start (snap_box, false, false);
2986 hbox->pack_start (*nudge_box, false, false);
2987 hbox->pack_start (panic_box, false, false);
2991 toolbar_base.set_name ("ToolBarBase");
2992 toolbar_base.add (toolbar_hbox);
2994 toolbar_frame.set_shadow_type (SHADOW_OUT);
2995 toolbar_frame.set_name ("BaseFrame");
2996 toolbar_frame.add (toolbar_base);
3000 Editor::setup_tooltips ()
3002 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3003 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3004 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3005 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3006 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3007 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
3008 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3009 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3010 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3011 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3012 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3013 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3014 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3015 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3016 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3017 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3018 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3019 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3020 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3021 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
3022 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
3023 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3027 Editor::midi_panic ()
3029 cerr << "MIDI panic\n";
3032 _session->midi_panic();
3037 Editor::setup_midi_toolbar ()
3041 /* Midi sound notes */
3042 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3043 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3044 midi_sound_notes.unset_flags (CAN_FOCUS);
3048 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3049 midi_panic_button.set_name("MidiPanicButton");
3050 act->connect_proxy (midi_panic_button);
3052 panic_box.pack_start (midi_sound_notes , true, true);
3053 panic_box.pack_start (midi_panic_button, true, true);
3057 Editor::convert_drop_to_paths (
3058 vector<string>& paths,
3059 const RefPtr<Gdk::DragContext>& /*context*/,
3062 const SelectionData& data,
3066 if (_session == 0) {
3070 vector<string> uris = data.get_uris();
3074 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3075 are actually URI lists. So do it by hand.
3078 if (data.get_target() != "text/plain") {
3082 /* Parse the "uri-list" format that Nautilus provides,
3083 where each pathname is delimited by \r\n.
3085 THERE MAY BE NO NULL TERMINATING CHAR!!!
3088 string txt = data.get_text();
3092 p = (const char *) malloc (txt.length() + 1);
3093 txt.copy ((char *) p, txt.length(), 0);
3094 ((char*)p)[txt.length()] = '\0';
3100 while (g_ascii_isspace (*p))
3104 while (*q && (*q != '\n') && (*q != '\r')) {
3111 while (q > p && g_ascii_isspace (*q))
3116 uris.push_back (string (p, q - p + 1));
3120 p = strchr (p, '\n');
3132 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3134 if ((*i).substr (0,7) == "file://") {
3137 PBD::url_decode (p);
3139 // scan forward past three slashes
3141 string::size_type slashcnt = 0;
3142 string::size_type n = 0;
3143 string::iterator x = p.begin();
3145 while (slashcnt < 3 && x != p.end()) {
3148 } else if (slashcnt == 3) {
3155 if (slashcnt != 3 || x == p.end()) {
3156 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3160 paths.push_back (p.substr (n - 1));
3168 Editor::new_tempo_section ()
3174 Editor::map_transport_state ()
3176 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3178 if (_session && _session->transport_stopped()) {
3179 have_pending_keyboard_selection = false;
3182 update_loop_range_view (true);
3187 Editor::State::State (PublicEditor const * e)
3189 selection = new Selection (e);
3192 Editor::State::~State ()
3198 Editor::begin_reversible_command (string name)
3201 _session->begin_reversible_command (name);
3206 Editor::commit_reversible_command ()
3209 _session->commit_reversible_command ();
3214 Editor::set_route_group_solo (Route& route, bool yn)
3216 RouteGroup *route_group;
3218 if ((route_group = route.route_group()) != 0) {
3219 route_group->apply (&Route::set_solo, yn, this);
3221 route.set_solo (yn, this);
3226 Editor::set_route_group_mute (Route& route, bool yn)
3228 RouteGroup *route_group = 0;
3230 if ((route_group = route.route_group()) != 0) {
3231 route_group->apply (&Route::set_mute, yn, this);
3233 route.set_mute (yn, this);
3238 Editor::history_changed ()
3242 if (undo_action && _session) {
3243 if (_session->undo_depth() == 0) {
3246 label = string_compose(_("Undo (%1)"), _session->next_undo());
3248 undo_action->property_label() = label;
3251 if (redo_action && _session) {
3252 if (_session->redo_depth() == 0) {
3255 label = string_compose(_("Redo (%1)"), _session->next_redo());
3257 redo_action->property_label() = label;
3262 Editor::duplicate_dialog (bool with_dialog)
3266 if (mouse_mode == MouseRange) {
3267 if (selection->time.length() == 0) {
3272 RegionSelection rs = get_regions_from_selection_and_entered ();
3274 if (mouse_mode != MouseRange && rs.empty()) {
3280 ArdourDialog win (_("Duplicate"));
3281 Label label (_("Number of duplications:"));
3282 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3283 SpinButton spinner (adjustment, 0.0, 1);
3286 win.get_vbox()->set_spacing (12);
3287 win.get_vbox()->pack_start (hbox);
3288 hbox.set_border_width (6);
3289 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3291 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3292 place, visually. so do this by hand.
3295 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3296 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3297 spinner.grab_focus();
3303 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3304 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3305 win.set_default_response (RESPONSE_ACCEPT);
3307 win.set_position (WIN_POS_MOUSE);
3309 spinner.grab_focus ();
3311 switch (win.run ()) {
3312 case RESPONSE_ACCEPT:
3318 times = adjustment.get_value();
3321 if (mouse_mode == MouseRange) {
3322 duplicate_selection (times);
3324 duplicate_some_regions (rs, times);
3329 Editor::show_verbose_canvas_cursor ()
3331 verbose_canvas_cursor->raise_to_top();
3332 verbose_canvas_cursor->show();
3333 verbose_cursor_visible = true;
3337 Editor::hide_verbose_canvas_cursor ()
3339 verbose_canvas_cursor->hide();
3340 verbose_cursor_visible = false;
3344 Editor::clamp_verbose_cursor_x (double x)
3349 x = min (_canvas_width - 200.0, x);
3355 Editor::clamp_verbose_cursor_y (double y)
3357 if (y < canvas_timebars_vsize) {
3358 y = canvas_timebars_vsize;
3360 y = min (_canvas_height - 50, y);
3366 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3368 verbose_canvas_cursor->property_text() = txt.c_str();
3373 track_canvas->get_pointer (x, y);
3374 track_canvas->window_to_world (x, y, wx, wy);
3379 /* don't get too close to the edge */
3380 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3381 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3383 show_verbose_canvas_cursor ();
3387 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3389 verbose_canvas_cursor->property_text() = txt.c_str();
3390 /* don't get too close to the edge */
3391 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3392 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3396 Editor::set_verbose_canvas_cursor_text (const string & txt)
3398 verbose_canvas_cursor->property_text() = txt.c_str();
3402 Editor::set_edit_mode (EditMode m)
3404 Config->set_edit_mode (m);
3408 Editor::cycle_edit_mode ()
3410 switch (Config->get_edit_mode()) {
3412 if (Profile->get_sae()) {
3413 Config->set_edit_mode (Lock);
3415 Config->set_edit_mode (Splice);
3419 Config->set_edit_mode (Lock);
3422 Config->set_edit_mode (Slide);
3428 Editor::edit_mode_selection_done ()
3430 Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ()));
3434 Editor::snap_type_selection_done ()
3436 string choice = snap_type_selector.get_active_text();
3437 SnapType snaptype = SnapToBeat;
3439 if (choice == _("Beats/2")) {
3440 snaptype = SnapToBeatDiv2;
3441 } else if (choice == _("Beats/3")) {
3442 snaptype = SnapToBeatDiv3;
3443 } else if (choice == _("Beats/4")) {
3444 snaptype = SnapToBeatDiv4;
3445 } else if (choice == _("Beats/5")) {
3446 snaptype = SnapToBeatDiv5;
3447 } else if (choice == _("Beats/6")) {
3448 snaptype = SnapToBeatDiv6;
3449 } else if (choice == _("Beats/7")) {
3450 snaptype = SnapToBeatDiv7;
3451 } else if (choice == _("Beats/8")) {
3452 snaptype = SnapToBeatDiv8;
3453 } else if (choice == _("Beats/10")) {
3454 snaptype = SnapToBeatDiv10;
3455 } else if (choice == _("Beats/12")) {
3456 snaptype = SnapToBeatDiv12;
3457 } else if (choice == _("Beats/14")) {
3458 snaptype = SnapToBeatDiv14;
3459 } else if (choice == _("Beats/16")) {
3460 snaptype = SnapToBeatDiv16;
3461 } else if (choice == _("Beats/20")) {
3462 snaptype = SnapToBeatDiv20;
3463 } else if (choice == _("Beats/24")) {
3464 snaptype = SnapToBeatDiv24;
3465 } else if (choice == _("Beats/28")) {
3466 snaptype = SnapToBeatDiv28;
3467 } else if (choice == _("Beats/32")) {
3468 snaptype = SnapToBeatDiv32;
3469 } else if (choice == _("Beats")) {
3470 snaptype = SnapToBeat;
3471 } else if (choice == _("Bars")) {
3472 snaptype = SnapToBar;
3473 } else if (choice == _("Marks")) {
3474 snaptype = SnapToMark;
3475 } else if (choice == _("Region starts")) {
3476 snaptype = SnapToRegionStart;
3477 } else if (choice == _("Region ends")) {
3478 snaptype = SnapToRegionEnd;
3479 } else if (choice == _("Region bounds")) {
3480 snaptype = SnapToRegionBoundary;
3481 } else if (choice == _("Region syncs")) {
3482 snaptype = SnapToRegionSync;
3483 } else if (choice == _("CD Frames")) {
3484 snaptype = SnapToCDFrame;
3485 } else if (choice == _("Timecode Frames")) {
3486 snaptype = SnapToTimecodeFrame;
3487 } else if (choice == _("Timecode Seconds")) {
3488 snaptype = SnapToTimecodeSeconds;
3489 } else if (choice == _("Timecode Minutes")) {
3490 snaptype = SnapToTimecodeMinutes;
3491 } else if (choice == _("Seconds")) {
3492 snaptype = SnapToSeconds;
3493 } else if (choice == _("Minutes")) {
3494 snaptype = SnapToMinutes;
3497 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3499 ract->set_active ();
3504 Editor::snap_mode_selection_done ()
3506 string choice = snap_mode_selector.get_active_text();
3507 SnapMode mode = SnapNormal;
3509 if (choice == _("No Grid")) {
3511 } else if (choice == _("Grid")) {
3513 } else if (choice == _("Magnetic")) {
3514 mode = SnapMagnetic;
3517 RefPtr<RadioAction> ract = snap_mode_action (mode);
3520 ract->set_active (true);
3525 Editor::cycle_edit_point (bool with_marker)
3527 switch (_edit_point) {
3529 set_edit_point_preference (EditAtPlayhead);
3531 case EditAtPlayhead:
3533 set_edit_point_preference (EditAtSelectedMarker);
3535 set_edit_point_preference (EditAtMouse);
3538 case EditAtSelectedMarker:
3539 set_edit_point_preference (EditAtMouse);
3545 Editor::edit_point_selection_done ()
3547 string choice = edit_point_selector.get_active_text();
3548 EditPoint ep = EditAtSelectedMarker;
3550 if (choice == _("Marker")) {
3551 set_edit_point_preference (EditAtSelectedMarker);
3552 } else if (choice == _("Playhead")) {
3553 set_edit_point_preference (EditAtPlayhead);
3555 set_edit_point_preference (EditAtMouse);
3558 RefPtr<RadioAction> ract = edit_point_action (ep);
3561 ract->set_active (true);
3566 Editor::zoom_focus_selection_done ()
3568 string choice = zoom_focus_selector.get_active_text();
3569 ZoomFocus focus_type = ZoomFocusLeft;
3571 if (choice == _("Left")) {
3572 focus_type = ZoomFocusLeft;
3573 } else if (choice == _("Right")) {
3574 focus_type = ZoomFocusRight;
3575 } else if (choice == _("Center")) {
3576 focus_type = ZoomFocusCenter;
3577 } else if (choice == _("Playhead")) {
3578 focus_type = ZoomFocusPlayhead;
3579 } else if (choice == _("Mouse")) {
3580 focus_type = ZoomFocusMouse;
3581 } else if (choice == _("Edit point")) {
3582 focus_type = ZoomFocusEdit;
3585 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3588 ract->set_active ();
3593 Editor::edit_controls_button_release (GdkEventButton* ev)
3595 if (Keyboard::is_context_menu_event (ev)) {
3596 ARDOUR_UI::instance()->add_route (this);
3602 Editor::mouse_select_button_release (GdkEventButton* ev)
3604 /* this handles just right-clicks */
3606 if (ev->button != 3) {
3614 Editor::set_zoom_focus (ZoomFocus f)
3616 string str = zoom_focus_strings[(int)f];
3618 if (str != zoom_focus_selector.get_active_text()) {
3619 zoom_focus_selector.set_active_text (str);
3622 if (zoom_focus != f) {
3625 ZoomFocusChanged (); /* EMIT_SIGNAL */
3632 Editor::ensure_float (Window& win)
3634 win.set_transient_for (*this);
3638 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3640 /* recover or initialize pane positions. do this here rather than earlier because
3641 we don't want the positions to change the child allocations, which they seem to do.
3647 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3659 width = default_width;
3660 height = default_height;
3662 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3664 prop = geometry->property ("x-size");
3666 width = atoi (prop->value());
3668 prop = geometry->property ("y-size");
3670 height = atoi (prop->value());
3674 if (which == static_cast<Paned*> (&edit_pane)) {
3676 if (done & Horizontal) {
3680 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3681 /* initial allocation is 90% to canvas, 10% to notebook */
3682 pos = (int) floor (alloc.get_width() * 0.90f);
3683 snprintf (buf, sizeof(buf), "%d", pos);
3685 pos = atoi (prop->value());
3688 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3689 edit_pane.set_position (pos);
3690 pre_maximal_horizontal_pane_position = pos;
3693 done = (Pane) (done | Horizontal);
3695 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3697 if (done & Vertical) {
3701 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3702 /* initial allocation is 90% to canvas, 10% to summary */
3703 pos = (int) floor (alloc.get_height() * 0.90f);
3704 snprintf (buf, sizeof(buf), "%d", pos);
3706 pos = atoi (prop->value());
3709 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3710 editor_summary_pane.set_position (pos);
3711 pre_maximal_vertical_pane_position = pos;
3714 done = (Pane) (done | Vertical);
3719 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3721 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3722 top_hbox.remove (toolbar_frame);
3727 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3729 if (toolbar_frame.get_parent() == 0) {
3730 top_hbox.pack_end (toolbar_frame);
3735 Editor::set_show_measures (bool yn)
3737 if (_show_measures != yn) {
3740 if ((_show_measures = yn) == true) {
3742 tempo_lines->show();
3750 Editor::toggle_follow_playhead ()
3752 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3754 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3755 set_follow_playhead (tact->get_active());
3760 Editor::set_follow_playhead (bool yn)
3762 if (_follow_playhead != yn) {
3763 if ((_follow_playhead = yn) == true) {
3765 reset_x_origin_to_follow_playhead ();
3772 Editor::toggle_stationary_playhead ()
3774 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3776 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3777 set_stationary_playhead (tact->get_active());
3782 Editor::set_stationary_playhead (bool yn)
3784 if (_stationary_playhead != yn) {
3785 if ((_stationary_playhead = yn) == true) {
3787 // FIXME need a 3.0 equivalent of this 2.X call
3788 // update_current_screen ();
3795 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3797 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3799 xfade->set_active (!xfade->active());
3804 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3806 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3808 xfade->set_follow_overlap (!xfade->following_overlap());
3813 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3815 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3821 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3825 switch (cew.run ()) {
3826 case RESPONSE_ACCEPT:
3833 PropertyChange all_crossfade_properties;
3834 all_crossfade_properties.add (ARDOUR::Properties::active);
3835 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3836 xfade->PropertyChanged (all_crossfade_properties);
3840 Editor::playlist_selector () const
3842 return *_playlist_selector;
3846 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3850 switch (_snap_type) {
3855 case SnapToBeatDiv32:
3858 case SnapToBeatDiv28:
3861 case SnapToBeatDiv24:
3864 case SnapToBeatDiv20:
3867 case SnapToBeatDiv16:
3870 case SnapToBeatDiv14:
3873 case SnapToBeatDiv12:
3876 case SnapToBeatDiv10:
3879 case SnapToBeatDiv8:
3882 case SnapToBeatDiv7:
3885 case SnapToBeatDiv6:
3888 case SnapToBeatDiv5:
3891 case SnapToBeatDiv4:
3894 case SnapToBeatDiv3:
3897 case SnapToBeatDiv2:
3903 return _session->tempo_map().meter_at (position).beats_per_bar();
3908 case SnapToTimecodeFrame:
3909 case SnapToTimecodeSeconds:
3910 case SnapToTimecodeMinutes:
3913 case SnapToRegionStart:
3914 case SnapToRegionEnd:
3915 case SnapToRegionSync:
3916 case SnapToRegionBoundary:
3926 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3930 ret = nudge_clock.current_duration (pos);
3931 next = ret + 1; /* XXXX fix me */
3937 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3939 ArdourDialog dialog (_("Playlist Deletion"));
3940 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3941 "If left alone, no audio files used by it will be cleaned.\n"
3942 "If deleted, audio files used by it alone by will cleaned."),
3945 dialog.set_position (WIN_POS_CENTER);
3946 dialog.get_vbox()->pack_start (label);
3950 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3951 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3952 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3954 switch (dialog.run ()) {
3955 case RESPONSE_ACCEPT:
3956 /* delete the playlist */
3960 case RESPONSE_REJECT:
3961 /* keep the playlist */
3973 Editor::audio_region_selection_covers (framepos_t where)
3975 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3976 if ((*a)->region()->covers (where)) {
3985 Editor::prepare_for_cleanup ()
3987 cut_buffer->clear_regions ();
3988 cut_buffer->clear_playlists ();
3990 selection->clear_regions ();
3991 selection->clear_playlists ();
3993 _regions->suspend_redisplay ();
3997 Editor::finish_cleanup ()
3999 _regions->resume_redisplay ();
4003 Editor::transport_loop_location()
4006 return _session->locations()->auto_loop_location();
4013 Editor::transport_punch_location()
4016 return _session->locations()->auto_punch_location();
4023 Editor::control_layout_scroll (GdkEventScroll* ev)
4025 if (Keyboard::some_magic_widget_has_focus()) {
4029 switch (ev->direction) {
4031 scroll_tracks_up_line ();
4035 case GDK_SCROLL_DOWN:
4036 scroll_tracks_down_line ();
4040 /* no left/right handling yet */
4048 Editor::session_state_saved (string)
4051 _snapshots->redisplay ();
4055 Editor::maximise_editing_space ()
4057 _mouse_mode_tearoff->set_visible (false);
4058 _tools_tearoff->set_visible (false);
4059 _zoom_tearoff->set_visible (false);
4061 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4062 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4063 pre_maximal_editor_width = this->get_width ();
4064 pre_maximal_editor_height = this->get_height ();
4066 if (post_maximal_horizontal_pane_position == 0) {
4067 post_maximal_horizontal_pane_position = edit_pane.get_width();
4070 if (post_maximal_vertical_pane_position == 0) {
4071 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4076 if (post_maximal_editor_width) {
4077 edit_pane.set_position (post_maximal_horizontal_pane_position -
4078 abs(post_maximal_editor_width - pre_maximal_editor_width));
4080 edit_pane.set_position (post_maximal_horizontal_pane_position);
4083 if (post_maximal_editor_height) {
4084 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4085 abs(post_maximal_editor_height - pre_maximal_editor_height));
4087 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4090 if (Config->get_keep_tearoffs()) {
4091 _mouse_mode_tearoff->set_visible (true);
4092 _tools_tearoff->set_visible (true);
4093 _zoom_tearoff->set_visible (true);
4099 Editor::restore_editing_space ()
4101 // user changed width/height of panes during fullscreen
4103 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4104 post_maximal_horizontal_pane_position = edit_pane.get_position();
4107 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4108 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4113 _mouse_mode_tearoff->set_visible (true);
4114 _tools_tearoff->set_visible (true);
4115 _zoom_tearoff->set_visible (true);
4116 post_maximal_editor_width = this->get_width();
4117 post_maximal_editor_height = this->get_height();
4119 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4120 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4124 * Make new playlists for a given track and also any others that belong
4125 * to the same active route group with the `edit' property.
4130 Editor::new_playlists (TimeAxisView* v)
4132 begin_reversible_command (_("new playlists"));
4133 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4134 _session->playlists->get (playlists);
4135 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4136 commit_reversible_command ();
4140 * Use a copy of the current playlist for a given track and also any others that belong
4141 * to the same active route group with the `edit' property.
4146 Editor::copy_playlists (TimeAxisView* v)
4148 begin_reversible_command (_("copy playlists"));
4149 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4150 _session->playlists->get (playlists);
4151 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4152 commit_reversible_command ();
4155 /** Clear the current playlist for a given track and also any others that belong
4156 * to the same active route group with the `edit' property.
4161 Editor::clear_playlists (TimeAxisView* v)
4163 begin_reversible_command (_("clear playlists"));
4164 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4165 _session->playlists->get (playlists);
4166 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4167 commit_reversible_command ();
4171 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4173 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4177 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4179 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4183 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4185 atv.clear_playlist ();
4189 Editor::on_key_press_event (GdkEventKey* ev)
4191 return key_press_focus_accelerator_handler (*this, ev);
4195 Editor::on_key_release_event (GdkEventKey* ev)
4197 return Gtk::Window::on_key_release_event (ev);
4198 // return key_press_focus_accelerator_handler (*this, ev);
4201 /** Queue up a change to the viewport x origin.
4202 * @param frame New x origin.
4205 Editor::reset_x_origin (framepos_t frame)
4207 queue_visual_change (frame);
4211 Editor::reset_y_origin (double y)
4213 queue_visual_change_y (y);
4217 Editor::reset_zoom (double fpu)
4219 queue_visual_change (fpu);
4223 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4225 reset_x_origin (frame);
4228 if (!no_save_visual) {
4229 undo_visual_stack.push_back (current_visual_state(false));
4233 Editor::VisualState*
4234 Editor::current_visual_state (bool with_tracks)
4236 VisualState* vs = new VisualState;
4237 vs->y_position = vertical_adjustment.get_value();
4238 vs->frames_per_unit = frames_per_unit;
4239 vs->leftmost_frame = leftmost_frame;
4240 vs->zoom_focus = zoom_focus;
4243 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4244 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4252 Editor::undo_visual_state ()
4254 if (undo_visual_stack.empty()) {
4258 redo_visual_stack.push_back (current_visual_state());
4260 VisualState* vs = undo_visual_stack.back();
4261 undo_visual_stack.pop_back();
4262 use_visual_state (*vs);
4266 Editor::redo_visual_state ()
4268 if (redo_visual_stack.empty()) {
4272 undo_visual_stack.push_back (current_visual_state());
4274 VisualState* vs = redo_visual_stack.back();
4275 redo_visual_stack.pop_back();
4276 use_visual_state (*vs);
4280 Editor::swap_visual_state ()
4282 if (undo_visual_stack.empty()) {
4283 redo_visual_state ();
4285 undo_visual_state ();
4290 Editor::use_visual_state (VisualState& vs)
4292 no_save_visual = true;
4294 _routes->suspend_redisplay ();
4296 vertical_adjustment.set_value (vs.y_position);
4298 set_zoom_focus (vs.zoom_focus);
4299 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4301 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4302 TrackViewList::iterator t;
4304 /* check if the track still exists - it could have been deleted */
4306 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4307 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4312 if (!vs.track_states.empty()) {
4313 _routes->update_visibility ();
4316 _routes->resume_redisplay ();
4318 no_save_visual = false;
4322 Editor::set_frames_per_unit (double fpu)
4324 /* this is the core function that controls the zoom level of the canvas. it is called
4325 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4328 if (fpu == frames_per_unit) {
4337 /* don't allow zooms that fit more than the maximum number
4338 of frames into an 800 pixel wide space.
4341 if (max_framepos / fpu < 800.0) {
4346 tempo_lines->tempo_map_changed();
4348 frames_per_unit = fpu;
4353 Editor::post_zoom ()
4355 // convert fpu to frame count
4357 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4359 if (frames_per_unit != zoom_range_clock.current_duration()) {
4360 zoom_range_clock.set (frames);
4363 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4364 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4365 (*i)->reshow_selection (selection->time);
4369 ZoomChanged (); /* EMIT_SIGNAL */
4371 //reset_scrolling_region ();
4373 if (playhead_cursor) {
4374 playhead_cursor->set_position (playhead_cursor->current_frame);
4377 refresh_location_display();
4378 _summary->set_overlays_dirty ();
4380 update_marker_labels ();
4386 Editor::queue_visual_change (framepos_t where)
4388 pending_visual_change.add (VisualChange::TimeOrigin);
4389 pending_visual_change.time_origin = where;
4390 ensure_visual_change_idle_handler ();
4394 Editor::queue_visual_change (double fpu)
4396 pending_visual_change.add (VisualChange::ZoomLevel);
4397 pending_visual_change.frames_per_unit = fpu;
4399 ensure_visual_change_idle_handler ();
4403 Editor::queue_visual_change_y (double y)
4405 pending_visual_change.add (VisualChange::YOrigin);
4406 pending_visual_change.y_origin = y;
4408 ensure_visual_change_idle_handler ();
4412 Editor::ensure_visual_change_idle_handler ()
4414 if (pending_visual_change.idle_handler_id < 0) {
4415 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4420 Editor::_idle_visual_changer (void* arg)
4422 return static_cast<Editor*>(arg)->idle_visual_changer ();
4426 Editor::idle_visual_changer ()
4428 VisualChange::Type p = pending_visual_change.pending;
4429 pending_visual_change.pending = (VisualChange::Type) 0;
4431 double const last_time_origin = horizontal_position ();
4433 if (p & VisualChange::TimeOrigin) {
4434 /* This is a bit of a hack, but set_frames_per_unit
4435 below will (if called) end up with the
4436 CrossfadeViews looking at Editor::leftmost_frame,
4437 and if we're changing origin and zoom in the same
4438 operation it will be the wrong value unless we
4442 leftmost_frame = pending_visual_change.time_origin;
4445 if (p & VisualChange::ZoomLevel) {
4446 set_frames_per_unit (pending_visual_change.frames_per_unit);
4448 compute_fixed_ruler_scale ();
4449 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4450 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4451 update_tempo_based_rulers ();
4453 if (p & VisualChange::TimeOrigin) {
4454 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4456 if (p & VisualChange::YOrigin) {
4457 vertical_adjustment.set_value (pending_visual_change.y_origin);
4460 if (last_time_origin == horizontal_position ()) {
4461 /* changed signal not emitted */
4462 update_fixed_rulers ();
4463 redisplay_tempo (true);
4466 _summary->set_overlays_dirty ();
4468 pending_visual_change.idle_handler_id = -1;
4469 return 0; /* this is always a one-shot call */
4472 struct EditorOrderTimeAxisSorter {
4473 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4474 return a->order () < b->order ();
4479 Editor::sort_track_selection (TrackViewList* sel)
4481 EditorOrderTimeAxisSorter cmp;
4486 selection->tracks.sort (cmp);
4491 Editor::get_preferred_edit_position (bool ignore_playhead)
4494 framepos_t where = 0;
4495 EditPoint ep = _edit_point;
4497 if (entered_marker) {
4498 return entered_marker->position();
4501 if (ignore_playhead && ep == EditAtPlayhead) {
4502 ep = EditAtSelectedMarker;
4506 case EditAtPlayhead:
4507 where = _session->audible_frame();
4510 case EditAtSelectedMarker:
4511 if (!selection->markers.empty()) {
4513 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4516 where = loc->start();
4527 if (!mouse_frame (where, ignored)) {
4528 /* XXX not right but what can we do ? */
4539 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4541 if (!_session) return;
4543 begin_reversible_command (cmd);
4547 if ((tll = transport_loop_location()) == 0) {
4548 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4549 XMLNode &before = _session->locations()->get_state();
4550 _session->locations()->add (loc, true);
4551 _session->set_auto_loop_location (loc);
4552 XMLNode &after = _session->locations()->get_state();
4553 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4555 XMLNode &before = tll->get_state();
4556 tll->set_hidden (false, this);
4557 tll->set (start, end);
4558 XMLNode &after = tll->get_state();
4559 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4562 commit_reversible_command ();
4566 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4568 if (!_session) return;
4570 begin_reversible_command (cmd);
4574 if ((tpl = transport_punch_location()) == 0) {
4575 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4576 XMLNode &before = _session->locations()->get_state();
4577 _session->locations()->add (loc, true);
4578 _session->set_auto_loop_location (loc);
4579 XMLNode &after = _session->locations()->get_state();
4580 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4583 XMLNode &before = tpl->get_state();
4584 tpl->set_hidden (false, this);
4585 tpl->set (start, end);
4586 XMLNode &after = tpl->get_state();
4587 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4590 commit_reversible_command ();
4593 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4594 * @param rs List to which found regions are added.
4595 * @param where Time to look at.
4596 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4599 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4601 const TrackViewList* tracks;
4604 tracks = &track_views;
4609 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4610 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4612 boost::shared_ptr<Track> tr;
4613 boost::shared_ptr<Playlist> pl;
4615 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4617 Playlist::RegionList* regions = pl->regions_at (
4618 (framepos_t) floor ( (double)where * tr->speed()));
4620 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4621 RegionView* rv = rtv->view()->find_view (*i);
4634 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4636 const TrackViewList* tracks;
4639 tracks = &track_views;
4644 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4645 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4647 boost::shared_ptr<Track> tr;
4648 boost::shared_ptr<Playlist> pl;
4650 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4652 Playlist::RegionList* regions = pl->regions_touched (
4653 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4655 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4657 RegionView* rv = rtv->view()->find_view (*i);
4670 /** Get regions using the following conditions:
4671 * 1. If the edit point is `mouse':
4672 * if the mouse is over a selected region, or no region, return all selected regions.
4673 * if the mouse is over an unselected region, return just that region.
4674 * 2. For all other edit points:
4675 * return the selected regions AND those that are both under the edit position
4676 * AND on a selected track, or on a track which is in the same active edit-enabled route group
4677 * as a selected region.
4679 * The rationale here is that the mouse edit point is special in that its position describes
4680 * both a time and a track; the other edit modes only describe a time.
4682 * @param rs Returned region list.
4686 Editor::get_regions_from_selection_and_edit_point ()
4688 if (_edit_point == EditAtMouse) {
4689 if (entered_regionview == 0 || selection->regions.contains (entered_regionview)) {
4690 return selection->regions;
4693 rs.add (entered_regionview);
4698 /* We're using the edit point, but its not EditAtMouse */
4700 /* Start with selected regions */
4701 RegionSelection rs = selection->regions;
4703 TrackViewList tracks = selection->tracks;
4705 /* Tracks is currently the set of selected tracks; add any other tracks that
4706 have regions that are in the same edit-activated route group as one of
4709 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4711 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4712 if (g && g->is_active() && g->is_edit()) {
4713 tracks.add (axis_views_from_routes (g->route_list()));
4718 if (!tracks.empty()) {
4719 /* now find regions that are at the edit position on those tracks */
4720 framepos_t const where = get_preferred_edit_position ();
4721 get_regions_at (rs, where, tracks);
4729 Editor::get_regions_from_selection_and_entered ()
4731 RegionSelection rs = selection->regions;
4733 if (rs.empty() && entered_regionview) {
4734 rs.add (entered_regionview);
4741 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4743 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4745 RouteTimeAxisView* tatv;
4747 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4749 boost::shared_ptr<Playlist> pl;
4750 vector<boost::shared_ptr<Region> > results;
4752 boost::shared_ptr<Track> tr;
4754 if ((tr = tatv->track()) == 0) {
4759 if ((pl = (tr->playlist())) != 0) {
4760 pl->get_region_list_equivalent_regions (region, results);
4763 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4764 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4765 regions.push_back (marv);
4774 Editor::show_rhythm_ferret ()
4776 if (rhythm_ferret == 0) {
4777 rhythm_ferret = new RhythmFerret(*this);
4780 rhythm_ferret->set_session (_session);
4781 rhythm_ferret->show ();
4782 rhythm_ferret->present ();
4786 Editor::first_idle ()
4788 MessageDialog* dialog = 0;
4790 if (track_views.size() > 1) {
4791 dialog = new MessageDialog (*this,
4792 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4797 ARDOUR_UI::instance()->flush_pending ();
4800 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4804 // first idle adds route children (automation tracks), so we need to redisplay here
4805 _routes->redisplay ();
4813 Editor::_idle_resize (gpointer arg)
4815 return ((Editor*)arg)->idle_resize ();
4819 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4821 if (resize_idle_id < 0) {
4822 resize_idle_id = g_idle_add (_idle_resize, this);
4823 _pending_resize_amount = 0;
4826 /* make a note of the smallest resulting height, so that we can clamp the
4827 lower limit at TimeAxisView::hSmall */
4829 int32_t min_resulting = INT32_MAX;
4831 _pending_resize_amount += h;
4832 _pending_resize_view = view;
4834 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4836 if (selection->tracks.contains (_pending_resize_view)) {
4837 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4838 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4842 if (min_resulting < 0) {
4847 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4848 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4852 /** Handle pending resizing of tracks */
4854 Editor::idle_resize ()
4856 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4858 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4859 selection->tracks.contains (_pending_resize_view)) {
4861 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4862 if (*i != _pending_resize_view) {
4863 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4868 _pending_resize_amount = 0;
4870 _group_tabs->set_dirty ();
4871 resize_idle_id = -1;
4879 ENSURE_GUI_THREAD (*this, &Editor::located);
4881 playhead_cursor->set_position (_session->audible_frame ());
4882 if (_follow_playhead && !_pending_initial_locate) {
4883 reset_x_origin_to_follow_playhead ();
4886 _pending_locate_request = false;
4887 _pending_initial_locate = false;
4891 Editor::region_view_added (RegionView *)
4893 _summary->set_dirty ();
4897 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4899 TrackViewList::const_iterator j = track_views.begin ();
4900 while (j != track_views.end()) {
4901 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4902 if (rtv && rtv->route() == r) {
4913 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4917 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4918 TimeAxisView* tv = axis_view_from_route (*i);
4929 Editor::handle_new_route (RouteList& routes)
4931 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4933 RouteTimeAxisView *rtv;
4934 list<RouteTimeAxisView*> new_views;
4936 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4937 boost::shared_ptr<Route> route = (*x);
4939 if (route->is_hidden() || route->is_monitor()) {
4943 DataType dt = route->input()->default_type();
4945 if (dt == ARDOUR::DataType::AUDIO) {
4946 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4947 } else if (dt == ARDOUR::DataType::MIDI) {
4948 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4950 throw unknown_type();
4953 new_views.push_back (rtv);
4954 track_views.push_back (rtv);
4956 rtv->effective_gain_display ();
4958 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4961 _routes->routes_added (new_views);
4963 if (show_editor_mixer_when_tracks_arrive) {
4964 show_editor_mixer (true);
4967 editor_list_button.set_sensitive (true);
4969 _summary->set_dirty ();
4973 Editor::timeaxisview_deleted (TimeAxisView *tv)
4975 if (_session && _session->deletion_in_progress()) {
4976 /* the situation is under control */
4980 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4982 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4984 _routes->route_removed (tv);
4986 if (tv == entered_track) {
4990 TimeAxisView::Children c = tv->get_child_list ();
4991 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4992 if (entered_track == i->get()) {
4997 /* remove it from the list of track views */
4999 TrackViewList::iterator i;
5001 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5002 i = track_views.erase (i);
5005 /* update whatever the current mixer strip is displaying, if revelant */
5007 boost::shared_ptr<Route> route;
5010 route = rtav->route ();
5013 if (current_mixer_strip && current_mixer_strip->route() == route) {
5015 TimeAxisView* next_tv;
5017 if (track_views.empty()) {
5019 } else if (i == track_views.end()) {
5020 next_tv = track_views.front();
5027 set_selected_mixer_strip (*next_tv);
5029 /* make the editor mixer strip go away setting the
5030 * button to inactive (which also unticks the menu option)
5033 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5039 Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/)
5041 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5043 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5044 // this will hide the mixer strip
5045 set_selected_mixer_strip (*tv);
5048 _routes->hide_track_in_display (*tv);
5052 Editor::sync_track_view_list_and_routes ()
5054 track_views = TrackViewList (_routes->views ());
5056 _summary->set_dirty ();
5057 _group_tabs->set_dirty ();
5059 return false; // do not call again (until needed)
5063 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5065 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5070 /** Find a RouteTimeAxisView by the ID of its route */
5072 Editor::get_route_view_by_route_id (PBD::ID& id) const
5074 RouteTimeAxisView* v;
5076 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5077 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5078 if(v->route()->id() == id) {
5088 Editor::fit_route_group (RouteGroup *g)
5090 TrackViewList ts = axis_views_from_routes (g->route_list ());
5095 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5097 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5100 _session->cancel_audition ();
5104 if (_session->is_auditioning()) {
5105 _session->cancel_audition ();
5106 if (r == last_audition_region) {
5111 _session->audition_region (r);
5112 last_audition_region = r;
5117 Editor::hide_a_region (boost::shared_ptr<Region> r)
5119 r->set_hidden (true);
5123 Editor::show_a_region (boost::shared_ptr<Region> r)
5125 r->set_hidden (false);
5129 Editor::audition_region_from_region_list ()
5131 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5135 Editor::hide_region_from_region_list ()
5137 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5141 Editor::show_region_in_region_list ()
5143 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5147 Editor::step_edit_status_change (bool yn)
5150 start_step_editing ();
5152 stop_step_editing ();
5157 Editor::start_step_editing ()
5159 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5163 Editor::stop_step_editing ()
5165 step_edit_connection.disconnect ();
5169 Editor::check_step_edit ()
5171 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5172 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5174 mtv->check_step_edit ();
5178 return true; // do it again, till we stop
5182 Editor::horizontal_scroll_left_press ()
5184 ++_scroll_callbacks;
5186 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5187 /* delay the first auto-repeat */
5191 double x = leftmost_position() - current_page_frames() / 5;
5198 /* do hacky auto-repeat */
5199 if (!_scroll_connection.connected ()) {
5200 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
5201 _scroll_callbacks = 0;
5208 Editor::horizontal_scroll_left_release ()
5210 _scroll_connection.disconnect ();
5214 Editor::horizontal_scroll_right_press ()
5216 ++_scroll_callbacks;
5218 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5219 /* delay the first auto-repeat */
5223 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5225 /* do hacky auto-repeat */
5226 if (!_scroll_connection.connected ()) {
5227 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
5228 _scroll_callbacks = 0;
5235 Editor::horizontal_scroll_right_release ()
5237 _scroll_connection.disconnect ();
5240 /** Queue a change for the Editor viewport x origin to follow the playhead */
5242 Editor::reset_x_origin_to_follow_playhead ()
5244 framepos_t const frame = playhead_cursor->current_frame;
5246 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5248 if (_session->transport_speed() < 0) {
5250 if (frame > (current_page_frames() / 2)) {
5251 center_screen (frame-(current_page_frames()/2));
5253 center_screen (current_page_frames()/2);
5258 if (frame < leftmost_frame) {
5261 if (_session->transport_rolling()) {
5262 /* rolling; end up with the playhead at the right of the page */
5263 l = frame - current_page_frames ();
5265 /* not rolling: end up with the playhead 3/4 of the way along the page */
5266 l = frame - (3 * current_page_frames() / 4);
5273 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5276 if (_session->transport_rolling()) {
5277 /* rolling: end up with the playhead on the left of the page */
5278 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5280 /* not rolling: end up with the playhead 1/4 of the way along the page */
5281 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5289 Editor::super_rapid_screen_update ()
5291 if (!_session || !_session->engine().running()) {
5295 /* METERING / MIXER STRIPS */
5297 /* update track meters, if required */
5298 if (is_mapped() && meters_running) {
5299 RouteTimeAxisView* rtv;
5300 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5301 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5302 rtv->fast_update ();
5307 /* and any current mixer strip */
5308 if (current_mixer_strip) {
5309 current_mixer_strip->fast_update ();
5312 /* PLAYHEAD AND VIEWPORT */
5314 framepos_t const frame = _session->audible_frame();
5316 /* There are a few reasons why we might not update the playhead / viewport stuff:
5318 * 1. we don't update things when there's a pending locate request, otherwise
5319 * when the editor requests a locate there is a chance that this method
5320 * will move the playhead before the locate request is processed, causing
5322 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5323 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5326 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5328 last_update_frame = frame;
5330 if (!_dragging_playhead) {
5331 playhead_cursor->set_position (frame);
5334 if (!_stationary_playhead) {
5336 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5337 reset_x_origin_to_follow_playhead ();
5342 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5346 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5347 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5348 if (target <= 0.0) {
5351 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5352 target = (target * 0.15) + (current * 0.85);
5358 set_horizontal_position (current);
5367 Editor::session_going_away ()
5369 _have_idled = false;
5371 _session_connections.drop_connections ();
5373 super_rapid_screen_update_connection.disconnect ();
5375 selection->clear ();
5376 cut_buffer->clear ();
5378 clicked_regionview = 0;
5379 clicked_axisview = 0;
5380 clicked_routeview = 0;
5381 clicked_crossfadeview = 0;
5382 entered_regionview = 0;
5384 last_update_frame = 0;
5387 playhead_cursor->canvas_item.hide ();
5389 /* rip everything out of the list displays */
5393 _route_groups->clear ();
5395 /* do this first so that deleting a track doesn't reset cms to null
5396 and thus cause a leak.
5399 if (current_mixer_strip) {
5400 if (current_mixer_strip->get_parent() != 0) {
5401 global_hpacker.remove (*current_mixer_strip);
5403 delete current_mixer_strip;
5404 current_mixer_strip = 0;
5407 /* delete all trackviews */
5409 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5412 track_views.clear ();
5414 zoom_range_clock.set_session (0);
5415 nudge_clock.set_session (0);
5417 editor_list_button.set_active(false);
5418 editor_list_button.set_sensitive(false);
5420 /* clear tempo/meter rulers */
5421 remove_metric_marks ();
5423 clear_marker_display ();
5425 delete current_bbt_points;
5426 current_bbt_points = 0;
5428 /* get rid of any existing editor mixer strip */
5430 WindowTitle title(Glib::get_application_name());
5431 title += _("Editor");
5433 set_title (title.get_string());
5435 SessionHandlePtr::session_going_away ();
5440 Editor::show_editor_list (bool yn)
5443 the_notebook.show();
5445 the_notebook.hide();
5450 Editor::change_region_layering_order ()
5452 framepos_t const position = get_preferred_edit_position ();
5454 if (!clicked_routeview) {
5455 if (layering_order_editor) {
5456 layering_order_editor->hide ();
5461 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5467 boost::shared_ptr<Playlist> pl = track->playlist();
5473 if (layering_order_editor == 0) {
5474 layering_order_editor = new RegionLayeringOrderEditor(*this);
5477 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5478 layering_order_editor->maybe_present ();
5482 Editor::update_region_layering_order_editor ()
5484 if (layering_order_editor && layering_order_editor->is_visible ()) {
5485 change_region_layering_order ();
5490 Editor::setup_fade_images ()
5492 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5493 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5494 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5495 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5496 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5498 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5499 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5500 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5501 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5502 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5506 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5508 Editor::action_menu_item (std::string const & name)
5510 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5513 return *manage (a->create_menu_item ());