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;
235 Gdk::Cursor* Editor::resize_left_cursor = 0;
236 Gdk::Cursor* Editor::resize_top_left_cursor = 0;
237 Gdk::Cursor* Editor::resize_top_cursor = 0;
238 Gdk::Cursor* Editor::resize_top_right_cursor = 0;
239 Gdk::Cursor* Editor::resize_right_cursor = 0;
240 Gdk::Cursor* Editor::resize_bottom_right_cursor = 0;
241 Gdk::Cursor* Editor::resize_bottom_cursor = 0;
242 Gdk::Cursor* Editor::resize_bottom_left_cursor = 0;
243 Gdk::Cursor* Editor::move_cursor = 0;
244 Gdk::Cursor* Editor::expand_left_right_cursor = 0;
245 Gdk::Cursor* Editor::expand_up_down_cursor = 0;
248 show_me_the_size (Requisition* r, const char* what)
250 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
255 pane_size_watcher (Paned* pane)
257 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
258 it is no longer accessible. so stop that. this doesn't happen on X11,
259 just the quartz backend.
264 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
266 gint pos = pane->get_position ();
268 if (pos > max_width_of_lhs) {
269 pane->set_position (max_width_of_lhs);
275 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
277 /* time display buttons */
278 , minsec_label (_("Mins:Secs"))
279 , bbt_label (_("Bars:Beats"))
280 , timecode_label (_("Timecode"))
281 , frame_label (_("Samples"))
282 , tempo_label (_("Tempo"))
283 , meter_label (_("Meter"))
284 , mark_label (_("Location Markers"))
285 , range_mark_label (_("Range Markers"))
286 , transport_mark_label (_("Loop/Punch Ranges"))
287 , cd_mark_label (_("CD Markers"))
288 , edit_packer (4, 4, true)
290 /* the values here don't matter: layout widgets
291 reset them as needed.
294 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
296 /* tool bar related */
298 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
300 , toolbar_selection_clock_table (2,3)
302 , automation_mode_button (_("mode"))
303 , global_automation_button (_("automation"))
305 , midi_panic_button (_("Panic"))
308 , image_socket_listener(0)
313 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
314 , meters_running(false)
315 , _pending_locate_request (false)
316 , _pending_initial_locate (false)
317 , _last_cut_copy_source_track (0)
319 , _region_selection_change_updates_region_list (true)
323 /* we are a singleton */
325 PublicEditor::_instance = this;
329 selection = new Selection (this);
330 cut_buffer = new Selection (this);
332 clicked_regionview = 0;
333 clicked_axisview = 0;
334 clicked_routeview = 0;
335 clicked_crossfadeview = 0;
336 clicked_control_point = 0;
337 last_update_frame = 0;
338 pre_press_cursor = 0;
339 _drags = new DragManager (this);
340 current_mixer_strip = 0;
341 current_bbt_points = 0;
344 snap_type_strings = I18N (_snap_type_strings);
345 snap_mode_strings = I18N (_snap_mode_strings);
346 zoom_focus_strings = I18N (_zoom_focus_strings);
347 edit_point_strings = I18N (_edit_point_strings);
348 #ifdef USE_RUBBERBAND
349 rb_opt_strings = I18N (_rb_opt_strings);
353 snap_threshold = 5.0;
354 bbt_beat_subdivision = 4;
357 last_autoscroll_x = 0;
358 last_autoscroll_y = 0;
359 autoscroll_active = false;
360 autoscroll_timeout_tag = -1;
365 current_interthread_info = 0;
366 _show_measures = true;
367 show_gain_after_trim = false;
368 verbose_cursor_on = true;
369 last_item_entered = 0;
371 have_pending_keyboard_selection = false;
372 _follow_playhead = true;
373 _stationary_playhead = false;
374 _xfade_visibility = true;
375 editor_ruler_menu = 0;
376 no_ruler_shown_update = false;
378 session_range_marker_menu = 0;
379 range_marker_menu = 0;
380 marker_menu_item = 0;
381 tempo_or_meter_marker_menu = 0;
382 transport_marker_menu = 0;
383 new_transport_marker_menu = 0;
384 editor_mixer_strip_width = Wide;
385 show_editor_mixer_when_tracks_arrive = false;
386 region_edit_menu_split_multichannel_item = 0;
387 region_edit_menu_split_item = 0;
390 current_stepping_trackview = 0;
392 entered_regionview = 0;
394 clear_entered_track = false;
397 button_release_can_deselect = true;
398 _dragging_playhead = false;
399 _dragging_edit_point = false;
400 select_new_marker = false;
402 layering_order_editor = 0;
404 no_save_visual = false;
407 scrubbing_direction = 0;
411 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
412 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
413 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
414 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
415 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
417 _edit_point = EditAtMouse;
418 _internal_editing = false;
419 current_canvas_cursor = 0;
421 frames_per_unit = 2048; /* too early to use reset_zoom () */
423 _scroll_callbacks = 0;
425 zoom_focus = ZoomFocusLeft;
426 set_zoom_focus (ZoomFocusLeft);
427 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
429 bbt_label.set_name ("EditorTimeButton");
430 bbt_label.set_size_request (-1, (int)timebar_height);
431 bbt_label.set_alignment (1.0, 0.5);
432 bbt_label.set_padding (5,0);
434 bbt_label.set_no_show_all();
435 minsec_label.set_name ("EditorTimeButton");
436 minsec_label.set_size_request (-1, (int)timebar_height);
437 minsec_label.set_alignment (1.0, 0.5);
438 minsec_label.set_padding (5,0);
439 minsec_label.hide ();
440 minsec_label.set_no_show_all();
441 timecode_label.set_name ("EditorTimeButton");
442 timecode_label.set_size_request (-1, (int)timebar_height);
443 timecode_label.set_alignment (1.0, 0.5);
444 timecode_label.set_padding (5,0);
445 timecode_label.hide ();
446 timecode_label.set_no_show_all();
447 frame_label.set_name ("EditorTimeButton");
448 frame_label.set_size_request (-1, (int)timebar_height);
449 frame_label.set_alignment (1.0, 0.5);
450 frame_label.set_padding (5,0);
452 frame_label.set_no_show_all();
454 tempo_label.set_name ("EditorTimeButton");
455 tempo_label.set_size_request (-1, (int)timebar_height);
456 tempo_label.set_alignment (1.0, 0.5);
457 tempo_label.set_padding (5,0);
459 tempo_label.set_no_show_all();
460 meter_label.set_name ("EditorTimeButton");
461 meter_label.set_size_request (-1, (int)timebar_height);
462 meter_label.set_alignment (1.0, 0.5);
463 meter_label.set_padding (5,0);
465 meter_label.set_no_show_all();
466 mark_label.set_name ("EditorTimeButton");
467 mark_label.set_size_request (-1, (int)timebar_height);
468 mark_label.set_alignment (1.0, 0.5);
469 mark_label.set_padding (5,0);
471 mark_label.set_no_show_all();
472 cd_mark_label.set_name ("EditorTimeButton");
473 cd_mark_label.set_size_request (-1, (int)timebar_height);
474 cd_mark_label.set_alignment (1.0, 0.5);
475 cd_mark_label.set_padding (5,0);
476 cd_mark_label.hide();
477 cd_mark_label.set_no_show_all();
478 range_mark_label.set_name ("EditorTimeButton");
479 range_mark_label.set_size_request (-1, (int)timebar_height);
480 range_mark_label.set_alignment (1.0, 0.5);
481 range_mark_label.set_padding (5,0);
482 range_mark_label.hide();
483 range_mark_label.set_no_show_all();
484 transport_mark_label.set_name ("EditorTimeButton");
485 transport_mark_label.set_size_request (-1, (int)timebar_height);
486 transport_mark_label.set_alignment (1.0, 0.5);
487 transport_mark_label.set_padding (5,0);
488 transport_mark_label.hide();
489 transport_mark_label.set_no_show_all();
491 initialize_rulers ();
492 initialize_canvas ();
493 _summary = new EditorSummary (this);
495 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
496 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
497 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
498 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
499 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
501 edit_controls_vbox.set_spacing (0);
502 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
503 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
505 HBox* h = manage (new HBox);
506 _group_tabs = new EditorGroupTabs (this);
507 h->pack_start (*_group_tabs, PACK_SHRINK);
508 h->pack_start (edit_controls_vbox);
509 controls_layout.add (*h);
511 controls_layout.set_name ("EditControlsBase");
512 controls_layout.add_events (Gdk::SCROLL_MASK);
513 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
515 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
516 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
517 controls_layout_size_request_connection = controls_layout.signal_size_request().connect (sigc::mem_fun (*this, &Editor::controls_layout_size_request));
521 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
522 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
523 0.0, 1.0, 100.0, 1.0));
524 pad_line_1->property_color_rgba() = 0xFF0000FF;
528 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
529 time_canvas_vbox.set_size_request (-1, -1);
531 ruler_label_event_box.add (ruler_label_vbox);
532 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
533 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
535 time_button_event_box.add (time_button_vbox);
536 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
537 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
539 /* these enable us to have a dedicated window (for cursor setting, etc.)
540 for the canvas areas.
543 track_canvas_event_box.add (*track_canvas);
545 time_canvas_event_box.add (time_canvas_vbox);
546 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
548 edit_packer.set_col_spacings (0);
549 edit_packer.set_row_spacings (0);
550 edit_packer.set_homogeneous (false);
551 edit_packer.set_border_width (0);
552 edit_packer.set_name ("EditorWindow");
554 /* labels for the rulers */
555 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
556 /* labels for the marker "tracks" */
557 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
559 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
561 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
563 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
565 bottom_hbox.set_border_width (2);
566 bottom_hbox.set_spacing (3);
568 _route_groups = new EditorRouteGroups (this);
569 _routes = new EditorRoutes (this);
570 _regions = new EditorRegions (this);
571 _snapshots = new EditorSnapshots (this);
572 _locations = new EditorLocations (this);
576 nlabel = manage (new Label (_("Regions")));
577 nlabel->set_angle (-90);
578 the_notebook.append_page (_regions->widget (), *nlabel);
579 nlabel = manage (new Label (_("Tracks & Busses")));
580 nlabel->set_angle (-90);
581 the_notebook.append_page (_routes->widget (), *nlabel);
582 nlabel = manage (new Label (_("Snapshots")));
583 nlabel->set_angle (-90);
584 the_notebook.append_page (_snapshots->widget (), *nlabel);
585 nlabel = manage (new Label (_("Route Groups")));
586 nlabel->set_angle (-90);
587 the_notebook.append_page (_route_groups->widget (), *nlabel);
588 nlabel = manage (new Label (_("Ranges & Marks")));
589 nlabel->set_angle (-90);
590 the_notebook.append_page (_locations->widget (), *nlabel);
592 the_notebook.set_show_tabs (true);
593 the_notebook.set_scrollable (true);
594 the_notebook.popup_disable ();
595 the_notebook.set_tab_pos (Gtk::POS_RIGHT);
596 the_notebook.show_all ();
598 post_maximal_editor_width = 0;
599 post_maximal_horizontal_pane_position = 0;
600 post_maximal_editor_height = 0;
601 post_maximal_vertical_pane_position = 0;
603 editor_summary_pane.pack1(edit_packer);
605 Button* summary_arrows_left_left = manage (new Button);
606 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
607 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
608 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
609 Button* summary_arrows_left_right = manage (new Button);
610 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
611 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
612 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
613 VBox* summary_arrows_left = manage (new VBox);
614 summary_arrows_left->pack_start (*summary_arrows_left_left);
615 summary_arrows_left->pack_start (*summary_arrows_left_right);
617 Button* summary_arrows_right_left = manage (new Button);
618 summary_arrows_right_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
619 summary_arrows_right_left->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press)));
620 summary_arrows_right_left->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_release));
621 Button* summary_arrows_right_right = manage (new Button);
622 summary_arrows_right_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
623 summary_arrows_right_right->signal_pressed().connect (sigc::hide_return (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press)));
624 summary_arrows_right_right->signal_released().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_release));
625 VBox* summary_arrows_right = manage (new VBox);
626 summary_arrows_right->pack_start (*summary_arrows_right_left);
627 summary_arrows_right->pack_start (*summary_arrows_right_right);
629 Frame* summary_frame = manage (new Frame);
630 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
631 summary_frame->add (*_summary);
632 summary_frame->show ();
634 _summary_hbox.pack_start (*summary_arrows_left, false, false);
635 _summary_hbox.pack_start (*summary_frame, true, true);
636 _summary_hbox.pack_start (*summary_arrows_right, false, false);
638 editor_summary_pane.pack2 (_summary_hbox);
640 edit_pane.pack1 (editor_summary_pane, true, true);
641 edit_pane.pack2 (the_notebook, false, true);
643 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
645 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
647 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
649 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
650 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
652 top_hbox.pack_start (toolbar_frame, false, true);
654 HBox *hbox = manage (new HBox);
655 hbox->pack_start (edit_pane, true, true);
657 global_vpacker.pack_start (top_hbox, false, false);
658 global_vpacker.pack_start (*hbox, true, true);
660 global_hpacker.pack_start (global_vpacker, true, true);
662 set_name ("EditorWindow");
663 add_accel_group (ActionManager::ui_manager->get_accel_group());
665 status_bar_hpacker.show ();
667 vpacker.pack_end (status_bar_hpacker, false, false);
668 vpacker.pack_end (global_hpacker, true, true);
670 /* register actions now so that set_state() can find them and set toggles/checks etc */
675 setup_midi_toolbar ();
677 _snap_type = SnapToBeat;
678 set_snap_to (_snap_type);
679 _snap_mode = SnapOff;
680 set_snap_mode (_snap_mode);
681 set_mouse_mode (MouseObject, true);
682 set_edit_point_preference (EditAtMouse, true);
684 _playlist_selector = new PlaylistSelector();
685 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
687 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
691 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
692 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
694 nudge_forward_button.set_name ("TransportButton");
695 nudge_backward_button.set_name ("TransportButton");
697 fade_context_menu.set_name ("ArdourContextMenu");
699 /* icons, titles, WM stuff */
701 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
702 Glib::RefPtr<Gdk::Pixbuf> icon;
704 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
705 window_icons.push_back (icon);
707 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
708 window_icons.push_back (icon);
710 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
711 window_icons.push_back (icon);
713 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
714 window_icons.push_back (icon);
716 if (!window_icons.empty()) {
717 set_icon_list (window_icons);
718 set_default_icon_list (window_icons);
721 WindowTitle title(Glib::get_application_name());
722 title += _("Editor");
723 set_title (title.get_string());
724 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
727 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
729 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
730 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
732 /* allow external control surfaces/protocols to do various things */
734 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
735 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
736 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
737 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
738 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
740 /* problematic: has to return a value and thus cannot be x-thread */
742 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
744 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
746 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
748 _ignore_region_action = false;
749 _last_region_menu_was_main = false;
750 _popup_region_menu_item = 0;
752 _show_marker_lines = false;
753 _over_region_trim_target = false;
758 setup_fade_images ();
764 if(image_socket_listener) {
765 if(image_socket_listener->is_connected())
767 image_socket_listener->close_connection() ;
770 delete image_socket_listener ;
771 image_socket_listener = 0 ;
776 delete _route_groups;
782 Editor::add_toplevel_controls (Container& cont)
784 vpacker.pack_start (cont, false, false);
789 Editor::catch_vanishing_regionview (RegionView *rv)
791 /* note: the selection will take care of the vanishing
792 audioregionview by itself.
795 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
799 if (clicked_regionview == rv) {
800 clicked_regionview = 0;
803 if (entered_regionview == rv) {
804 set_entered_regionview (0);
807 if (!_all_region_actions_sensitized) {
808 sensitize_all_region_actions (true);
813 Editor::set_entered_regionview (RegionView* rv)
815 if (rv == entered_regionview) {
819 if (entered_regionview) {
820 entered_regionview->exited ();
823 if ((entered_regionview = rv) != 0) {
824 entered_regionview->entered (internal_editing ());
827 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
828 /* This RegionView entry might have changed what region actions
829 are allowed, so sensitize them all in case a key is pressed.
831 sensitize_all_region_actions (true);
836 Editor::set_entered_track (TimeAxisView* tav)
839 entered_track->exited ();
842 if ((entered_track = tav) != 0) {
843 entered_track->entered ();
848 Editor::show_window ()
850 if (! is_visible ()) {
853 /* re-hide editor list if necessary */
854 editor_list_button_toggled ();
856 /* re-hide summary widget if necessary */
857 parameter_changed ("show-summary");
859 parameter_changed ("show-edit-group-tabs");
861 /* now reset all audio_time_axis heights, because widgets might need
867 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
868 tv = (static_cast<TimeAxisView*>(*i));
877 Editor::instant_save ()
879 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
884 _session->add_instant_xml(get_state());
886 Config->add_instant_xml(get_state());
891 Editor::zoom_adjustment_changed ()
897 double fpu = zoom_range_clock.current_duration() / _canvas_width;
901 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
902 } else if (fpu > _session->current_end_frame() / _canvas_width) {
903 fpu = _session->current_end_frame() / _canvas_width;
904 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
911 Editor::control_scroll (float fraction)
913 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
919 double step = fraction * current_page_frames();
922 _control_scroll_target is an optional<T>
924 it acts like a pointer to an framepos_t, with
925 a operator conversion to boolean to check
926 that it has a value could possibly use
927 playhead_cursor->current_frame to store the
928 value and a boolean in the class to know
929 when it's out of date
932 if (!_control_scroll_target) {
933 _control_scroll_target = _session->transport_frame();
934 _dragging_playhead = true;
937 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
938 *_control_scroll_target = 0;
939 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
940 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
942 *_control_scroll_target += (framepos_t) floor (step);
945 /* move visuals, we'll catch up with it later */
947 playhead_cursor->set_position (*_control_scroll_target);
948 UpdateAllTransportClocks (*_control_scroll_target);
950 if (*_control_scroll_target > (current_page_frames() / 2)) {
951 /* try to center PH in window */
952 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
958 Now we do a timeout to actually bring the session to the right place
959 according to the playhead. This is to avoid reading disk buffers on every
960 call to control_scroll, which is driven by ScrollTimeline and therefore
961 probably by a control surface wheel which can generate lots of events.
963 /* cancel the existing timeout */
965 control_scroll_connection.disconnect ();
967 /* add the next timeout */
969 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
973 Editor::deferred_control_scroll (framepos_t /*target*/)
975 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
976 // reset for next stream
977 _control_scroll_target = boost::none;
978 _dragging_playhead = false;
983 Editor::access_action (std::string action_group, std::string action_item)
989 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
992 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1000 Editor::on_realize ()
1002 Window::on_realize ();
1007 Editor::map_position_change (framepos_t frame)
1009 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1011 if (_session == 0) {
1015 if (_follow_playhead) {
1016 center_screen (frame);
1019 playhead_cursor->set_position (frame);
1023 Editor::center_screen (framepos_t frame)
1025 double page = _canvas_width * frames_per_unit;
1027 /* if we're off the page, then scroll.
1030 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1031 center_screen_internal (frame, page);
1036 Editor::center_screen_internal (framepos_t frame, float page)
1041 frame -= (framepos_t) page;
1046 reset_x_origin (frame);
1051 Editor::update_title ()
1053 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1056 bool dirty = _session->dirty();
1058 string session_name;
1060 if (_session->snap_name() != _session->name()) {
1061 session_name = _session->snap_name();
1063 session_name = _session->name();
1067 session_name = "*" + session_name;
1070 WindowTitle title(session_name);
1071 title += Glib::get_application_name();
1072 set_title (title.get_string());
1077 Editor::set_session (Session *t)
1079 SessionHandlePtr::set_session (t);
1085 zoom_range_clock.set_session (_session);
1086 _playlist_selector->set_session (_session);
1087 nudge_clock.set_session (_session);
1088 _summary->set_session (_session);
1089 _group_tabs->set_session (_session);
1090 _route_groups->set_session (_session);
1091 _regions->set_session (_session);
1092 _snapshots->set_session (_session);
1093 _routes->set_session (_session);
1094 _locations->set_session (_session);
1096 if (rhythm_ferret) {
1097 rhythm_ferret->set_session (_session);
1100 if (analysis_window) {
1101 analysis_window->set_session (_session);
1105 sfbrowser->set_session (_session);
1108 compute_fixed_ruler_scale ();
1110 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1111 set_state (*node, Stateful::loading_state_version);
1113 /* catch up with the playhead */
1115 _session->request_locate (playhead_cursor->current_frame);
1116 _pending_initial_locate = true;
1120 /* These signals can all be emitted by a non-GUI thread. Therefore the
1121 handlers for them must not attempt to directly interact with the GUI,
1122 but use Gtkmm2ext::UI::instance()->call_slot();
1125 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1126 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1127 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1128 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1129 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1130 _session->TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_just_timecode, this), gui_context());
1131 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1132 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1133 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1134 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1135 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1136 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1137 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1138 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1139 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1141 if (Profile->get_sae()) {
1146 nframes_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1147 nudge_clock.set_mode(AudioClock::BBT);
1148 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1151 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1154 playhead_cursor->canvas_item.show ();
1156 Location* loc = _session->locations()->auto_loop_location();
1158 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1159 if (loc->start() == loc->end()) {
1160 loc->set_end (loc->start() + 1);
1162 _session->locations()->add (loc, false);
1163 _session->set_auto_loop_location (loc);
1166 loc->set_name (_("Loop"));
1169 loc = _session->locations()->auto_punch_location();
1171 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1172 if (loc->start() == loc->end()) {
1173 loc->set_end (loc->start() + 1);
1175 _session->locations()->add (loc, false);
1176 _session->set_auto_punch_location (loc);
1179 loc->set_name (_("Punch"));
1182 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1183 Config->map_parameters (pc);
1184 _session->config.map_parameters (pc);
1186 refresh_location_display ();
1188 restore_ruler_visibility ();
1189 //tempo_map_changed (PropertyChange (0));
1190 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1192 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1193 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1196 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1197 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1200 switch (_snap_type) {
1201 case SnapToRegionStart:
1202 case SnapToRegionEnd:
1203 case SnapToRegionSync:
1204 case SnapToRegionBoundary:
1205 build_region_boundary_cache ();
1212 /* register for undo history */
1213 _session->register_with_memento_command_factory(_id, this);
1215 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1217 start_updating_meters ();
1221 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1223 if (a->get_name() == "RegionMenu") {
1224 /* When the main menu's region menu is opened, we setup the actions so that they look right
1225 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1226 so we resensitize all region actions when the entered regionview or the region selection
1227 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1228 happens after the region context menu is opened. So we set a flag here, too.
1232 sensitize_the_right_region_actions ();
1233 _last_region_menu_was_main = true;
1238 Editor::build_cursors ()
1240 using namespace Gdk;
1243 Glib::RefPtr<Gdk::Pixbuf> zoom_in_cursor_pixbuf (::get_icon ("zoom_in_cursor"));
1244 zoom_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_in_cursor_pixbuf, 5, 5);
1248 Glib::RefPtr<Gdk::Pixbuf> zoom_out_cursor_pixbuf (::get_icon ("zoom_out_cursor"));
1249 zoom_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_out_cursor_pixbuf, 5, 5);
1252 Gdk::Color fbg ("#ffffff" );
1253 Gdk::Color ffg ("#000000" );
1256 RefPtr<Bitmap> source, mask;
1258 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1259 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1260 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1264 RefPtr<Bitmap> source, mask;
1265 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1266 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1267 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1271 RefPtr<Bitmap> bits;
1272 char pix[4] = { 0, 0, 0, 0 };
1273 bits = Bitmap::create (pix, 2, 2);
1275 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1279 RefPtr<Bitmap> bits;
1280 char pix[4] = { 0, 0, 0, 0 };
1281 bits = Bitmap::create (pix, 2, 2);
1283 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1287 Glib::RefPtr<Gdk::Pixbuf> grabber_pixbuf (::get_icon ("grabber"));
1288 grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0);
1292 Glib::RefPtr<Gdk::Pixbuf> grabber_note_pixbuf (::get_icon ("grabber_note"));
1293 grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10);
1297 Glib::RefPtr<Gdk::Pixbuf> grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point"));
1298 grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17);
1301 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1302 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1305 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_left_cursor"));
1306 left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11);
1310 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_right_cursor"));
1311 right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11);
1315 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_in_cursor"));
1316 fade_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 0, 0);
1320 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_out_cursor"));
1321 fade_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 29, 0);
1325 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_left_cursor"));
1326 resize_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 10);
1330 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_left_cursor"));
1331 resize_top_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 3);
1335 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_cursor"));
1336 resize_top_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 10, 3);
1340 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_right_cursor"));
1341 resize_top_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 18, 3);
1345 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_right_cursor"));
1346 resize_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 24, 10);
1350 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_right_cursor"));
1351 resize_bottom_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 18, 18);
1355 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_cursor"));
1356 resize_bottom_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 10, 24);
1360 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_left_cursor"));
1361 resize_bottom_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 18);
1365 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("move_cursor"));
1366 move_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 11, 11);
1370 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("expand_left_right_cursor"));
1371 expand_left_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 11, 4);
1375 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("expand_up_down_cursor"));
1376 expand_up_down_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 4, 11);
1379 selector_cursor = new Gdk::Cursor (XTERM);
1380 time_fx_cursor = new Gdk::Cursor (SIZING);
1381 wait_cursor = new Gdk::Cursor (WATCH);
1382 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1383 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1384 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1385 midi_resize_cursor = new Gdk::Cursor (SIZING);
1386 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1387 up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW);
1390 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1392 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1394 using namespace Menu_Helpers;
1395 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1398 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1402 MenuList& items (fade_context_menu.items());
1406 switch (item_type) {
1408 case FadeInHandleItem:
1409 if (arv->audio_region()->fade_in_active()) {
1410 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1412 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1415 items.push_back (SeparatorElem());
1417 if (Profile->get_sae()) {
1419 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1420 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1427 *_fade_in_images[FadeLinear],
1428 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1432 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1437 *_fade_in_images[FadeFast],
1438 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1441 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1446 *_fade_in_images[FadeLogB],
1447 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1455 *_fade_in_images[FadeLogA],
1456 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *_fade_in_images[FadeSlow],
1465 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1468 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 case FadeOutHandleItem:
1475 if (arv->audio_region()->fade_out_active()) {
1476 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1478 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1481 items.push_back (SeparatorElem());
1483 if (Profile->get_sae()) {
1484 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1485 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1491 *_fade_out_images[FadeLinear],
1492 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *_fade_out_images[FadeFast],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *_fade_out_images[FadeLogB],
1511 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 *_fade_out_images[FadeLogA],
1520 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1523 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1528 *_fade_out_images[FadeSlow],
1529 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1532 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1538 fatal << _("programming error: ")
1539 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1544 fade_context_menu.popup (button, time);
1548 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1550 using namespace Menu_Helpers;
1551 Menu* (Editor::*build_menu_function)();
1554 switch (item_type) {
1556 case RegionViewName:
1557 case RegionViewNameHighlight:
1558 case LeftFrameHandle:
1559 case RightFrameHandle:
1560 if (with_selection) {
1561 build_menu_function = &Editor::build_track_selection_context_menu;
1563 build_menu_function = &Editor::build_track_region_context_menu;
1568 if (with_selection) {
1569 build_menu_function = &Editor::build_track_selection_context_menu;
1571 build_menu_function = &Editor::build_track_context_menu;
1575 case CrossfadeViewItem:
1576 build_menu_function = &Editor::build_track_crossfade_context_menu;
1580 if (clicked_routeview->track()) {
1581 build_menu_function = &Editor::build_track_context_menu;
1583 build_menu_function = &Editor::build_track_bus_context_menu;
1588 /* probably shouldn't happen but if it does, we don't care */
1592 menu = (this->*build_menu_function)();
1593 menu->set_name ("ArdourContextMenu");
1595 /* now handle specific situations */
1597 switch (item_type) {
1599 case RegionViewName:
1600 case RegionViewNameHighlight:
1601 case LeftFrameHandle:
1602 case RightFrameHandle:
1603 if (!with_selection) {
1604 if (region_edit_menu_split_item) {
1605 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1606 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1608 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1611 if (region_edit_menu_split_multichannel_item) {
1612 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1613 region_edit_menu_split_multichannel_item->set_sensitive (true);
1615 region_edit_menu_split_multichannel_item->set_sensitive (false);
1624 case CrossfadeViewItem:
1631 /* probably shouldn't happen but if it does, we don't care */
1635 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1637 /* Bounce to disk */
1639 using namespace Menu_Helpers;
1640 MenuList& edit_items = menu->items();
1642 edit_items.push_back (SeparatorElem());
1644 switch (clicked_routeview->audio_track()->freeze_state()) {
1645 case AudioTrack::NoFreeze:
1646 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1649 case AudioTrack::Frozen:
1650 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1653 case AudioTrack::UnFrozen:
1654 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1660 if (item_type == StreamItem && clicked_routeview) {
1661 clicked_routeview->build_underlay_menu(menu);
1664 /* When the region menu is opened, we setup the actions so that they look right
1667 sensitize_the_right_region_actions ();
1668 _last_region_menu_was_main = false;
1670 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1671 menu->popup (button, time);
1675 Editor::build_track_context_menu ()
1677 using namespace Menu_Helpers;
1679 MenuList& edit_items = track_context_menu.items();
1682 add_dstream_context_items (edit_items);
1683 return &track_context_menu;
1687 Editor::build_track_bus_context_menu ()
1689 using namespace Menu_Helpers;
1691 MenuList& edit_items = track_context_menu.items();
1694 add_bus_context_items (edit_items);
1695 return &track_context_menu;
1699 Editor::build_track_region_context_menu ()
1701 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_region_context_menu.items();
1705 /* we've just cleared the track region context menu, so the menu that these
1706 two items were on will have disappeared; stop them dangling.
1708 region_edit_menu_split_item = 0;
1709 region_edit_menu_split_multichannel_item = 0;
1711 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1714 boost::shared_ptr<Track> tr;
1715 boost::shared_ptr<Playlist> pl;
1717 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1718 mode and so offering region context is somewhat confusing.
1720 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1721 framepos_t const framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1722 uint32_t regions_at = pl->count_regions_at (framepos);
1723 add_region_context_items (edit_items, regions_at > 1);
1727 add_dstream_context_items (edit_items);
1729 return &track_region_context_menu;
1733 Editor::build_track_crossfade_context_menu ()
1735 using namespace Menu_Helpers;
1736 MenuList& edit_items = track_crossfade_context_menu.items();
1737 edit_items.clear ();
1739 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1742 boost::shared_ptr<Track> tr;
1743 boost::shared_ptr<Playlist> pl;
1744 boost::shared_ptr<AudioPlaylist> apl;
1746 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1748 AudioPlaylist::Crossfades xfades;
1750 apl->crossfades_at (get_preferred_edit_position (), xfades);
1752 bool many = xfades.size() > 1;
1754 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1755 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1758 framepos_t framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1759 uint32_t regions_at = pl->count_regions_at (framepos);
1760 add_region_context_items (edit_items, regions_at > 1);
1764 add_dstream_context_items (edit_items);
1766 return &track_crossfade_context_menu;
1770 Editor::analyze_region_selection ()
1772 if (analysis_window == 0) {
1773 analysis_window = new AnalysisWindow();
1776 analysis_window->set_session(_session);
1778 analysis_window->show_all();
1781 analysis_window->set_regionmode();
1782 analysis_window->analyze();
1784 analysis_window->present();
1788 Editor::analyze_range_selection()
1790 if (analysis_window == 0) {
1791 analysis_window = new AnalysisWindow();
1794 analysis_window->set_session(_session);
1796 analysis_window->show_all();
1799 analysis_window->set_rangemode();
1800 analysis_window->analyze();
1802 analysis_window->present();
1806 Editor::build_track_selection_context_menu ()
1808 using namespace Menu_Helpers;
1809 MenuList& edit_items = track_selection_context_menu.items();
1810 edit_items.clear ();
1812 add_selection_context_items (edit_items);
1813 // edit_items.push_back (SeparatorElem());
1814 // add_dstream_context_items (edit_items);
1816 return &track_selection_context_menu;
1819 /** Add context menu items relevant to crossfades.
1820 * @param edit_items List to add the items to.
1823 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1825 using namespace Menu_Helpers;
1826 Menu *xfade_menu = manage (new Menu);
1827 MenuList& items = xfade_menu->items();
1828 xfade_menu->set_name ("ArdourContextMenu");
1831 if (xfade->active()) {
1837 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1838 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1840 if (xfade->can_follow_overlap()) {
1842 if (xfade->following_overlap()) {
1843 str = _("Convert to Short");
1845 str = _("Convert to Full");
1848 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1852 str = xfade->out()->name();
1854 str += xfade->in()->name();
1856 str = _("Crossfade");
1859 edit_items.push_back (MenuElem (str, *xfade_menu));
1860 edit_items.push_back (SeparatorElem());
1864 Editor::xfade_edit_left_region ()
1866 if (clicked_crossfadeview) {
1867 clicked_crossfadeview->left_view.show_region_editor ();
1872 Editor::xfade_edit_right_region ()
1874 if (clicked_crossfadeview) {
1875 clicked_crossfadeview->right_view.show_region_editor ();
1880 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1882 using namespace Menu_Helpers;
1884 /* OK, stick the region submenu at the top of the list, and then add
1888 /* we have to hack up the region name because "_" has a special
1889 meaning for menu titles.
1892 RegionSelection rs = get_regions_from_selection_and_entered ();
1894 string::size_type pos = 0;
1895 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1897 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1898 menu_item_name.replace (pos, 1, "__");
1902 if (_popup_region_menu_item == 0) {
1903 _popup_region_menu_item = new MenuItem (menu_item_name);
1904 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1905 _popup_region_menu_item->show ();
1907 _popup_region_menu_item->set_label (menu_item_name);
1910 edit_items.push_back (*_popup_region_menu_item);
1911 if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1912 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1914 edit_items.push_back (SeparatorElem());
1917 /** Add context menu items relevant to selection ranges.
1918 * @param edit_items List to add the items to.
1921 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1923 using namespace Menu_Helpers;
1925 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1926 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1928 edit_items.push_back (SeparatorElem());
1929 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1931 if (!selection->regions.empty()) {
1932 edit_items.push_back (SeparatorElem());
1933 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)));
1934 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)));
1937 edit_items.push_back (SeparatorElem());
1938 edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1939 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1941 edit_items.push_back (SeparatorElem());
1942 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1944 edit_items.push_back (SeparatorElem());
1945 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1946 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1951 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1953 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1954 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1958 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1959 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1960 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1961 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1966 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1968 using namespace Menu_Helpers;
1972 Menu *play_menu = manage (new Menu);
1973 MenuList& play_items = play_menu->items();
1974 play_menu->set_name ("ArdourContextMenu");
1976 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1977 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1978 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1979 play_items.push_back (SeparatorElem());
1980 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1982 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1986 Menu *select_menu = manage (new Menu);
1987 MenuList& select_items = select_menu->items();
1988 select_menu->set_name ("ArdourContextMenu");
1990 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1992 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1993 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1994 select_items.push_back (SeparatorElem());
1995 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1996 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1997 select_items.push_back (SeparatorElem());
1998 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1999 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2000 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2001 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2002 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2003 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2004 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2006 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2010 Menu *cutnpaste_menu = manage (new Menu);
2011 MenuList& cutnpaste_items = cutnpaste_menu->items();
2012 cutnpaste_menu->set_name ("ArdourContextMenu");
2014 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2015 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2016 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2018 cutnpaste_items.push_back (SeparatorElem());
2020 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2021 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2023 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2025 /* Adding new material */
2027 edit_items.push_back (SeparatorElem());
2028 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2029 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2033 Menu *nudge_menu = manage (new Menu());
2034 MenuList& nudge_items = nudge_menu->items();
2035 nudge_menu->set_name ("ArdourContextMenu");
2037 edit_items.push_back (SeparatorElem());
2038 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2039 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2040 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2041 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2043 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2047 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2049 using namespace Menu_Helpers;
2053 Menu *play_menu = manage (new Menu);
2054 MenuList& play_items = play_menu->items();
2055 play_menu->set_name ("ArdourContextMenu");
2057 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2058 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2059 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2063 Menu *select_menu = manage (new Menu);
2064 MenuList& select_items = select_menu->items();
2065 select_menu->set_name ("ArdourContextMenu");
2067 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2068 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2069 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2070 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2071 select_items.push_back (SeparatorElem());
2072 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2073 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2074 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2075 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2077 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2081 Menu *cutnpaste_menu = manage (new Menu);
2082 MenuList& cutnpaste_items = cutnpaste_menu->items();
2083 cutnpaste_menu->set_name ("ArdourContextMenu");
2085 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2086 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2087 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2089 Menu *nudge_menu = manage (new Menu());
2090 MenuList& nudge_items = nudge_menu->items();
2091 nudge_menu->set_name ("ArdourContextMenu");
2093 edit_items.push_back (SeparatorElem());
2094 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2095 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2096 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2097 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2099 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2103 Editor::snap_type() const
2109 Editor::snap_mode() const
2115 Editor::set_snap_to (SnapType st)
2117 unsigned int snap_ind = (unsigned int)st;
2121 if (snap_ind > snap_type_strings.size() - 1) {
2123 _snap_type = (SnapType)snap_ind;
2126 string str = snap_type_strings[snap_ind];
2128 if (str != snap_type_selector.get_active_text()) {
2129 snap_type_selector.set_active_text (str);
2134 switch (_snap_type) {
2135 case SnapToBeatDiv32:
2136 case SnapToBeatDiv28:
2137 case SnapToBeatDiv24:
2138 case SnapToBeatDiv20:
2139 case SnapToBeatDiv16:
2140 case SnapToBeatDiv14:
2141 case SnapToBeatDiv12:
2142 case SnapToBeatDiv10:
2143 case SnapToBeatDiv8:
2144 case SnapToBeatDiv7:
2145 case SnapToBeatDiv6:
2146 case SnapToBeatDiv5:
2147 case SnapToBeatDiv4:
2148 case SnapToBeatDiv3:
2149 case SnapToBeatDiv2:
2150 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2151 update_tempo_based_rulers ();
2154 case SnapToRegionStart:
2155 case SnapToRegionEnd:
2156 case SnapToRegionSync:
2157 case SnapToRegionBoundary:
2158 build_region_boundary_cache ();
2166 SnapChanged (); /* EMIT SIGNAL */
2170 Editor::set_snap_mode (SnapMode mode)
2173 string str = snap_mode_strings[(int)mode];
2175 if (str != snap_mode_selector.get_active_text ()) {
2176 snap_mode_selector.set_active_text (str);
2182 Editor::set_edit_point_preference (EditPoint ep, bool force)
2184 bool changed = (_edit_point != ep);
2187 string str = edit_point_strings[(int)ep];
2189 if (str != edit_point_selector.get_active_text ()) {
2190 edit_point_selector.set_active_text (str);
2193 set_canvas_cursor ();
2195 if (!force && !changed) {
2199 const char* action=NULL;
2201 switch (_edit_point) {
2202 case EditAtPlayhead:
2203 action = "edit-at-playhead";
2205 case EditAtSelectedMarker:
2206 action = "edit-at-marker";
2209 action = "edit-at-mouse";
2213 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2215 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2219 bool in_track_canvas;
2221 if (!mouse_frame (foo, in_track_canvas)) {
2222 in_track_canvas = false;
2225 reset_canvas_action_sensitivity (in_track_canvas);
2231 Editor::set_state (const XMLNode& node, int /*version*/)
2233 const XMLProperty* prop;
2235 int x, y, xoff, yoff;
2238 if ((prop = node.property ("id")) != 0) {
2239 _id = prop->value ();
2242 g.base_width = default_width;
2243 g.base_height = default_height;
2249 if ((geometry = find_named_node (node, "geometry")) != 0) {
2253 if ((prop = geometry->property("x_size")) == 0) {
2254 prop = geometry->property ("x-size");
2257 g.base_width = atoi(prop->value());
2259 if ((prop = geometry->property("y_size")) == 0) {
2260 prop = geometry->property ("y-size");
2263 g.base_height = atoi(prop->value());
2266 if ((prop = geometry->property ("x_pos")) == 0) {
2267 prop = geometry->property ("x-pos");
2270 x = atoi (prop->value());
2273 if ((prop = geometry->property ("y_pos")) == 0) {
2274 prop = geometry->property ("y-pos");
2277 y = atoi (prop->value());
2280 if ((prop = geometry->property ("x_off")) == 0) {
2281 prop = geometry->property ("x-off");
2284 xoff = atoi (prop->value());
2286 if ((prop = geometry->property ("y_off")) == 0) {
2287 prop = geometry->property ("y-off");
2290 yoff = atoi (prop->value());
2294 set_default_size (g.base_width, g.base_height);
2297 if (_session && (prop = node.property ("playhead"))) {
2299 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2300 playhead_cursor->set_position (pos);
2302 playhead_cursor->set_position (0);
2305 if ((prop = node.property ("mixer-width"))) {
2306 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2309 if ((prop = node.property ("zoom-focus"))) {
2310 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2313 if ((prop = node.property ("zoom"))) {
2314 reset_zoom (PBD::atof (prop->value()));
2316 reset_zoom (frames_per_unit);
2319 if ((prop = node.property ("snap-to"))) {
2320 set_snap_to ((SnapType) atoi (prop->value()));
2323 if ((prop = node.property ("snap-mode"))) {
2324 set_snap_mode ((SnapMode) atoi (prop->value()));
2327 if ((prop = node.property ("mouse-mode"))) {
2328 MouseMode m = str2mousemode(prop->value());
2329 set_mouse_mode (m, true);
2331 set_mouse_mode (MouseObject, true);
2334 if ((prop = node.property ("left-frame")) != 0){
2336 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2337 reset_x_origin (pos);
2341 if ((prop = node.property ("y-origin")) != 0) {
2342 reset_y_origin (atof (prop->value ()));
2345 if ((prop = node.property ("internal-edit"))) {
2346 bool yn = string_is_affirmative (prop->value());
2347 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2349 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2350 tact->set_active (!yn);
2351 tact->set_active (yn);
2355 if ((prop = node.property ("join-object-range"))) {
2356 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2359 if ((prop = node.property ("edit-point"))) {
2360 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2363 if ((prop = node.property ("show-measures"))) {
2364 bool yn = string_is_affirmative (prop->value());
2365 _show_measures = yn;
2366 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2368 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2369 /* do it twice to force the change */
2370 tact->set_active (!yn);
2371 tact->set_active (yn);
2375 if ((prop = node.property ("follow-playhead"))) {
2376 bool yn = string_is_affirmative (prop->value());
2377 set_follow_playhead (yn);
2378 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2380 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2381 if (tact->get_active() != yn) {
2382 tact->set_active (yn);
2387 if ((prop = node.property ("stationary-playhead"))) {
2388 bool yn = (prop->value() == "yes");
2389 set_stationary_playhead (yn);
2390 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2392 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2393 if (tact->get_active() != yn) {
2394 tact->set_active (yn);
2399 if ((prop = node.property ("region-list-sort-type"))) {
2400 RegionListSortType st;
2401 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2404 if ((prop = node.property ("xfades-visible"))) {
2405 bool yn = string_is_affirmative (prop->value());
2406 _xfade_visibility = !yn;
2407 // set_xfade_visibility (yn);
2410 if ((prop = node.property ("show-editor-mixer"))) {
2412 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2415 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2416 bool yn = string_is_affirmative (prop->value());
2418 /* do it twice to force the change */
2420 tact->set_active (!yn);
2421 tact->set_active (yn);
2424 if ((prop = node.property ("show-editor-list"))) {
2426 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2429 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2430 bool yn = string_is_affirmative (prop->value());
2432 /* do it twice to force the change */
2434 tact->set_active (!yn);
2435 tact->set_active (yn);
2438 if ((prop = node.property (X_("editor-list-page")))) {
2439 the_notebook.set_current_page (atoi (prop->value ()));
2442 if ((prop = node.property (X_("show-marker-lines")))) {
2443 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2445 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2446 bool yn = string_is_affirmative (prop->value ());
2448 tact->set_active (!yn);
2449 tact->set_active (yn);
2452 XMLNodeList children = node.children ();
2453 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2454 selection->set_state (**i, Stateful::current_state_version);
2455 _regions->set_state (**i);
2462 Editor::get_state ()
2464 XMLNode* node = new XMLNode ("Editor");
2467 _id.print (buf, sizeof (buf));
2468 node->add_property ("id", buf);
2470 if (is_realized()) {
2471 Glib::RefPtr<Gdk::Window> win = get_window();
2473 int x, y, xoff, yoff, width, height;
2474 win->get_root_origin(x, y);
2475 win->get_position(xoff, yoff);
2476 win->get_size(width, height);
2478 XMLNode* geometry = new XMLNode ("geometry");
2480 snprintf(buf, sizeof(buf), "%d", width);
2481 geometry->add_property("x-size", string(buf));
2482 snprintf(buf, sizeof(buf), "%d", height);
2483 geometry->add_property("y-size", string(buf));
2484 snprintf(buf, sizeof(buf), "%d", x);
2485 geometry->add_property("x-pos", string(buf));
2486 snprintf(buf, sizeof(buf), "%d", y);
2487 geometry->add_property("y-pos", string(buf));
2488 snprintf(buf, sizeof(buf), "%d", xoff);
2489 geometry->add_property("x-off", string(buf));
2490 snprintf(buf, sizeof(buf), "%d", yoff);
2491 geometry->add_property("y-off", string(buf));
2492 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2493 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2494 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2495 geometry->add_property("edit-vertical-pane-pos", string(buf));
2497 node->add_child_nocopy (*geometry);
2500 maybe_add_mixer_strip_width (*node);
2502 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2503 node->add_property ("zoom-focus", buf);
2504 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2505 node->add_property ("zoom", buf);
2506 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2507 node->add_property ("snap-to", buf);
2508 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2509 node->add_property ("snap-mode", buf);
2511 node->add_property ("edit-point", enum_2_string (_edit_point));
2513 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2514 node->add_property ("playhead", buf);
2515 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2516 node->add_property ("left-frame", buf);
2517 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2518 node->add_property ("y-origin", buf);
2520 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2521 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2522 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2523 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2524 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2525 node->add_property ("mouse-mode", enum2str(mouse_mode));
2526 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2527 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2529 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2531 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2535 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2537 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2538 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2541 snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
2542 node->add_property (X_("editor-list-page"), buf);
2544 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2546 node->add_child_nocopy (selection->get_state ());
2547 node->add_child_nocopy (_regions->get_state ());
2554 /** @param y y offset from the top of all trackviews.
2555 * @return pair: TimeAxisView that y is over, layer index.
2556 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2557 * in stacked region display mode, otherwise 0.
2559 std::pair<TimeAxisView *, layer_t>
2560 Editor::trackview_by_y_position (double y)
2562 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2564 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2570 return std::make_pair ( (TimeAxisView *) 0, 0);
2573 /** Snap a position to the grid, if appropriate, taking into account current
2574 * grid settings and also the state of any snap modifier keys that may be pressed.
2575 * @param start Position to snap.
2576 * @param event Event to get current key modifier information from, or 0.
2579 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2581 if (!_session || !event) {
2585 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2586 if (_snap_mode == SnapOff) {
2587 snap_to_internal (start, direction, for_mark);
2590 if (_snap_mode != SnapOff) {
2591 snap_to_internal (start, direction, for_mark);
2597 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2599 if (!_session || _snap_mode == SnapOff) {
2603 snap_to_internal (start, direction, for_mark);
2607 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2609 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2610 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2612 switch (_snap_type) {
2613 case SnapToTimecodeFrame:
2614 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2615 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2617 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2621 case SnapToTimecodeSeconds:
2622 if (_session->timecode_offset_negative())
2624 start += _session->timecode_offset ();
2626 start -= _session->timecode_offset ();
2628 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2629 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2631 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2634 if (_session->timecode_offset_negative())
2636 start -= _session->timecode_offset ();
2638 start += _session->timecode_offset ();
2642 case SnapToTimecodeMinutes:
2643 if (_session->timecode_offset_negative())
2645 start += _session->timecode_offset ();
2647 start -= _session->timecode_offset ();
2649 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2650 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2652 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2654 if (_session->timecode_offset_negative())
2656 start -= _session->timecode_offset ();
2658 start += _session->timecode_offset ();
2662 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2668 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2670 const framepos_t one_second = _session->frame_rate();
2671 const framepos_t one_minute = _session->frame_rate() * 60;
2672 framepos_t presnap = start;
2676 switch (_snap_type) {
2677 case SnapToTimecodeFrame:
2678 case SnapToTimecodeSeconds:
2679 case SnapToTimecodeMinutes:
2680 return timecode_snap_to_internal (start, direction, for_mark);
2683 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2684 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2686 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2691 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2692 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2694 start = (framepos_t) floor ((double) start / one_second) * one_second;
2699 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2700 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2702 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2707 start = _session->tempo_map().round_to_bar (start, direction);
2711 start = _session->tempo_map().round_to_beat (start, direction);
2714 case SnapToBeatDiv32:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2717 case SnapToBeatDiv28:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2720 case SnapToBeatDiv24:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2723 case SnapToBeatDiv20:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2726 case SnapToBeatDiv16:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2729 case SnapToBeatDiv14:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2732 case SnapToBeatDiv12:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2735 case SnapToBeatDiv10:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2738 case SnapToBeatDiv8:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2741 case SnapToBeatDiv7:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2744 case SnapToBeatDiv6:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2747 case SnapToBeatDiv5:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2750 case SnapToBeatDiv4:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2753 case SnapToBeatDiv3:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2756 case SnapToBeatDiv2:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2765 _session->locations()->marks_either_side (start, before, after);
2767 if (before == max_framepos) {
2769 } else if (after == max_framepos) {
2771 } else if (before != max_framepos && after != max_framepos) {
2772 /* have before and after */
2773 if ((start - before) < (after - start)) {
2782 case SnapToRegionStart:
2783 case SnapToRegionEnd:
2784 case SnapToRegionSync:
2785 case SnapToRegionBoundary:
2786 if (!region_boundary_cache.empty()) {
2788 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2789 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2791 if (direction > 0) {
2792 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2797 if (next != region_boundary_cache.begin ()) {
2802 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2803 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2805 if (start > (p + n) / 2) {
2814 switch (_snap_mode) {
2820 if (presnap > start) {
2821 if (presnap > (start + unit_to_frame(snap_threshold))) {
2825 } else if (presnap < start) {
2826 if (presnap < (start - unit_to_frame(snap_threshold))) {
2832 /* handled at entry */
2840 Editor::setup_toolbar ()
2844 /* Mode Buttons (tool selection) */
2846 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2847 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2848 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2849 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2850 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2851 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2852 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2853 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2855 HBox* mode_box = manage(new HBox);
2856 mode_box->set_border_width (2);
2857 mode_box->set_spacing(4);
2859 /* table containing mode buttons */
2861 HBox* mouse_mode_button_box = manage (new HBox ());
2863 if (Profile->get_sae()) {
2864 mouse_mode_button_box->pack_start (mouse_move_button);
2866 mouse_mode_button_box->pack_start (mouse_move_button);
2867 mouse_mode_button_box->pack_start (join_object_range_button);
2868 mouse_mode_button_box->pack_start (mouse_select_button);
2871 mouse_mode_button_box->pack_start (mouse_zoom_button);
2873 if (!Profile->get_sae()) {
2874 mouse_mode_button_box->pack_start (mouse_gain_button);
2877 mouse_mode_button_box->pack_start (mouse_timefx_button);
2878 mouse_mode_button_box->pack_start (mouse_audition_button);
2879 mouse_mode_button_box->pack_start (internal_edit_button);
2881 vector<string> edit_mode_strings;
2882 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2883 if (!Profile->get_sae()) {
2884 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2886 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2888 edit_mode_selector.set_name ("EditModeSelector");
2889 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2890 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2892 mode_box->pack_start (edit_mode_selector);
2893 mode_box->pack_start (*mouse_mode_button_box);
2895 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2896 _mouse_mode_tearoff->set_name ("MouseModeBase");
2897 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2899 if (Profile->get_sae()) {
2900 _mouse_mode_tearoff->set_can_be_torn_off (false);
2903 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window()));
2905 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2906 &_mouse_mode_tearoff->tearoff_window(), 1));
2907 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908 &_mouse_mode_tearoff->tearoff_window()));
2909 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910 &_mouse_mode_tearoff->tearoff_window(), 1));
2912 mouse_move_button.set_mode (false);
2913 mouse_select_button.set_mode (false);
2914 mouse_gain_button.set_mode (false);
2915 mouse_zoom_button.set_mode (false);
2916 mouse_timefx_button.set_mode (false);
2917 mouse_audition_button.set_mode (false);
2918 join_object_range_button.set_mode (false);
2920 mouse_move_button.set_name ("MouseModeButton");
2921 mouse_select_button.set_name ("MouseModeButton");
2922 mouse_gain_button.set_name ("MouseModeButton");
2923 mouse_zoom_button.set_name ("MouseModeButton");
2924 mouse_timefx_button.set_name ("MouseModeButton");
2925 mouse_audition_button.set_name ("MouseModeButton");
2926 internal_edit_button.set_name ("MouseModeButton");
2927 join_object_range_button.set_name ("MouseModeButton");
2929 mouse_move_button.unset_flags (CAN_FOCUS);
2930 mouse_select_button.unset_flags (CAN_FOCUS);
2931 mouse_gain_button.unset_flags (CAN_FOCUS);
2932 mouse_zoom_button.unset_flags (CAN_FOCUS);
2933 mouse_timefx_button.unset_flags (CAN_FOCUS);
2934 mouse_audition_button.unset_flags (CAN_FOCUS);
2935 internal_edit_button.unset_flags (CAN_FOCUS);
2936 join_object_range_button.unset_flags (CAN_FOCUS);
2940 _zoom_box.set_spacing (1);
2941 _zoom_box.set_border_width (0);
2943 zoom_in_button.set_name ("EditorTimeButton");
2944 zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2945 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2947 zoom_out_button.set_name ("EditorTimeButton");
2948 zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2949 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2951 zoom_out_full_button.set_name ("EditorTimeButton");
2952 zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2953 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2955 zoom_focus_selector.set_name ("ZoomFocusSelector");
2956 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2957 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2959 _zoom_box.pack_start (zoom_out_button, false, false);
2960 _zoom_box.pack_start (zoom_in_button, false, false);
2961 _zoom_box.pack_start (zoom_out_full_button, false, false);
2963 _zoom_box.pack_start (zoom_focus_selector);
2965 /* Track zoom buttons */
2966 tav_expand_button.set_name ("TrackHeightButton");
2967 tav_expand_button.set_size_request(-1,20);
2968 tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2969 tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2971 tav_shrink_button.set_name ("TrackHeightButton");
2972 tav_shrink_button.set_size_request(-1,20);
2973 tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2974 tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2976 _zoom_box.pack_start (tav_shrink_button);
2977 _zoom_box.pack_start (tav_expand_button);
2979 _zoom_tearoff = manage (new TearOff (_zoom_box));
2981 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window()));
2983 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window(), 0));
2985 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_zoom_tearoff->tearoff_window()));
2987 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_zoom_tearoff->tearoff_window(), 0));
2990 snap_box.set_spacing (1);
2991 snap_box.set_border_width (2);
2993 snap_type_selector.set_name ("SnapTypeSelector");
2994 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2995 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2997 snap_mode_selector.set_name ("SnapModeSelector");
2998 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2999 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3001 edit_point_selector.set_name ("EditPointSelector");
3002 set_popdown_strings (edit_point_selector, edit_point_strings, true);
3003 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3005 snap_box.pack_start (snap_mode_selector, false, false);
3006 snap_box.pack_start (snap_type_selector, false, false);
3007 snap_box.pack_start (edit_point_selector, false, false);
3011 HBox *nudge_box = manage (new HBox);
3012 nudge_box->set_spacing(1);
3013 nudge_box->set_border_width (2);
3015 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3016 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3018 nudge_box->pack_start (nudge_backward_button, false, false);
3019 nudge_box->pack_start (nudge_forward_button, false, false);
3020 nudge_box->pack_start (nudge_clock, false, false);
3023 /* Pack everything in... */
3025 HBox* hbox = manage (new HBox);
3026 hbox->set_spacing(10);
3028 _tools_tearoff = manage (new TearOff (*hbox));
3029 _tools_tearoff->set_name ("MouseModeBase");
3030 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3032 if (Profile->get_sae()) {
3033 _tools_tearoff->set_can_be_torn_off (false);
3036 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3037 &_tools_tearoff->tearoff_window()));
3038 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3039 &_tools_tearoff->tearoff_window(), 0));
3040 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3041 &_tools_tearoff->tearoff_window()));
3042 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3043 &_tools_tearoff->tearoff_window(), 0));
3045 toolbar_hbox.set_spacing (10);
3046 toolbar_hbox.set_border_width (1);
3048 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3049 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3050 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3052 hbox->pack_start (snap_box, false, false);
3053 hbox->pack_start (*nudge_box, false, false);
3054 hbox->pack_start (panic_box, false, false);
3058 toolbar_base.set_name ("ToolBarBase");
3059 toolbar_base.add (toolbar_hbox);
3061 toolbar_frame.set_shadow_type (SHADOW_OUT);
3062 toolbar_frame.set_name ("BaseFrame");
3063 toolbar_frame.add (toolbar_base);
3067 Editor::setup_tooltips ()
3069 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3070 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3071 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3072 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3073 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3074 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
3075 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3076 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3077 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3078 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3079 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3080 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3081 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3082 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3083 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3084 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3085 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3086 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3087 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3088 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
3089 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
3090 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3094 Editor::midi_panic ()
3096 cerr << "MIDI panic\n";
3099 _session->midi_panic();
3104 Editor::setup_midi_toolbar ()
3108 /* Midi sound notes */
3109 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3110 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3111 midi_sound_notes.unset_flags (CAN_FOCUS);
3115 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3116 midi_panic_button.set_name("MidiPanicButton");
3117 act->connect_proxy (midi_panic_button);
3119 panic_box.pack_start (midi_sound_notes , true, true);
3120 panic_box.pack_start (midi_panic_button, true, true);
3124 Editor::convert_drop_to_paths (
3125 vector<string>& paths,
3126 const RefPtr<Gdk::DragContext>& /*context*/,
3129 const SelectionData& data,
3133 if (_session == 0) {
3137 vector<string> uris = data.get_uris();
3141 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3142 are actually URI lists. So do it by hand.
3145 if (data.get_target() != "text/plain") {
3149 /* Parse the "uri-list" format that Nautilus provides,
3150 where each pathname is delimited by \r\n.
3152 THERE MAY BE NO NULL TERMINATING CHAR!!!
3155 string txt = data.get_text();
3159 p = (const char *) malloc (txt.length() + 1);
3160 txt.copy ((char *) p, txt.length(), 0);
3161 ((char*)p)[txt.length()] = '\0';
3167 while (g_ascii_isspace (*p))
3171 while (*q && (*q != '\n') && (*q != '\r')) {
3178 while (q > p && g_ascii_isspace (*q))
3183 uris.push_back (string (p, q - p + 1));
3187 p = strchr (p, '\n');
3199 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3201 if ((*i).substr (0,7) == "file://") {
3204 PBD::url_decode (p);
3206 // scan forward past three slashes
3208 string::size_type slashcnt = 0;
3209 string::size_type n = 0;
3210 string::iterator x = p.begin();
3212 while (slashcnt < 3 && x != p.end()) {
3215 } else if (slashcnt == 3) {
3222 if (slashcnt != 3 || x == p.end()) {
3223 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3227 paths.push_back (p.substr (n - 1));
3235 Editor::new_tempo_section ()
3241 Editor::map_transport_state ()
3243 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3245 if (_session && _session->transport_stopped()) {
3246 have_pending_keyboard_selection = false;
3249 update_loop_range_view (true);
3254 Editor::State::State (PublicEditor const * e)
3256 selection = new Selection (e);
3259 Editor::State::~State ()
3265 Editor::begin_reversible_command (string name)
3268 _session->begin_reversible_command (name);
3273 Editor::commit_reversible_command ()
3276 _session->commit_reversible_command ();
3281 Editor::set_route_group_solo (Route& route, bool yn)
3283 RouteGroup *route_group;
3285 if ((route_group = route.route_group()) != 0) {
3286 route_group->apply (&Route::set_solo, yn, this);
3288 route.set_solo (yn, this);
3293 Editor::set_route_group_mute (Route& route, bool yn)
3295 RouteGroup *route_group = 0;
3297 if ((route_group = route.route_group()) != 0) {
3298 route_group->apply (&Route::set_mute, yn, this);
3300 route.set_mute (yn, this);
3305 Editor::history_changed ()
3309 if (undo_action && _session) {
3310 if (_session->undo_depth() == 0) {
3313 label = string_compose(_("Undo (%1)"), _session->next_undo());
3315 undo_action->property_label() = label;
3318 if (redo_action && _session) {
3319 if (_session->redo_depth() == 0) {
3322 label = string_compose(_("Redo (%1)"), _session->next_redo());
3324 redo_action->property_label() = label;
3329 Editor::duplicate_dialog (bool with_dialog)
3333 if (mouse_mode == MouseRange) {
3334 if (selection->time.length() == 0) {
3339 RegionSelection rs = get_regions_from_selection_and_entered ();
3341 if (mouse_mode != MouseRange && rs.empty()) {
3347 ArdourDialog win (_("Duplicate"));
3348 Label label (_("Number of duplications:"));
3349 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3350 SpinButton spinner (adjustment, 0.0, 1);
3353 win.get_vbox()->set_spacing (12);
3354 win.get_vbox()->pack_start (hbox);
3355 hbox.set_border_width (6);
3356 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3358 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3359 place, visually. so do this by hand.
3362 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3363 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3364 spinner.grab_focus();
3370 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3371 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3372 win.set_default_response (RESPONSE_ACCEPT);
3374 win.set_position (WIN_POS_MOUSE);
3376 spinner.grab_focus ();
3378 switch (win.run ()) {
3379 case RESPONSE_ACCEPT:
3385 times = adjustment.get_value();
3388 if (mouse_mode == MouseRange) {
3389 duplicate_selection (times);
3391 duplicate_some_regions (rs, times);
3396 Editor::show_verbose_canvas_cursor ()
3398 verbose_canvas_cursor->raise_to_top();
3399 verbose_canvas_cursor->show();
3400 verbose_cursor_visible = true;
3404 Editor::hide_verbose_canvas_cursor ()
3406 verbose_canvas_cursor->hide();
3407 verbose_cursor_visible = false;
3411 Editor::clamp_verbose_cursor_x (double x)
3416 x = min (_canvas_width - 200.0, x);
3422 Editor::clamp_verbose_cursor_y (double y)
3424 if (y < canvas_timebars_vsize) {
3425 y = canvas_timebars_vsize;
3427 y = min (_canvas_height - 50, y);
3433 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3435 verbose_canvas_cursor->property_text() = txt.c_str();
3440 track_canvas->get_pointer (x, y);
3441 track_canvas->window_to_world (x, y, wx, wy);
3446 /* don't get too close to the edge */
3447 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3448 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3450 show_verbose_canvas_cursor ();
3454 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3456 verbose_canvas_cursor->property_text() = txt.c_str();
3457 /* don't get too close to the edge */
3458 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3459 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3463 Editor::set_verbose_canvas_cursor_text (const string & txt)
3465 verbose_canvas_cursor->property_text() = txt.c_str();
3469 Editor::set_edit_mode (EditMode m)
3471 Config->set_edit_mode (m);
3475 Editor::cycle_edit_mode ()
3477 switch (Config->get_edit_mode()) {
3479 if (Profile->get_sae()) {
3480 Config->set_edit_mode (Lock);
3482 Config->set_edit_mode (Splice);
3486 Config->set_edit_mode (Lock);
3489 Config->set_edit_mode (Slide);
3495 Editor::edit_mode_selection_done ()
3497 Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ()));
3501 Editor::snap_type_selection_done ()
3503 string choice = snap_type_selector.get_active_text();
3504 SnapType snaptype = SnapToBeat;
3506 if (choice == _("Beats/2")) {
3507 snaptype = SnapToBeatDiv2;
3508 } else if (choice == _("Beats/3")) {
3509 snaptype = SnapToBeatDiv3;
3510 } else if (choice == _("Beats/4")) {
3511 snaptype = SnapToBeatDiv4;
3512 } else if (choice == _("Beats/5")) {
3513 snaptype = SnapToBeatDiv5;
3514 } else if (choice == _("Beats/6")) {
3515 snaptype = SnapToBeatDiv6;
3516 } else if (choice == _("Beats/7")) {
3517 snaptype = SnapToBeatDiv7;
3518 } else if (choice == _("Beats/8")) {
3519 snaptype = SnapToBeatDiv8;
3520 } else if (choice == _("Beats/10")) {
3521 snaptype = SnapToBeatDiv10;
3522 } else if (choice == _("Beats/12")) {
3523 snaptype = SnapToBeatDiv12;
3524 } else if (choice == _("Beats/14")) {
3525 snaptype = SnapToBeatDiv14;
3526 } else if (choice == _("Beats/16")) {
3527 snaptype = SnapToBeatDiv16;
3528 } else if (choice == _("Beats/20")) {
3529 snaptype = SnapToBeatDiv20;
3530 } else if (choice == _("Beats/24")) {
3531 snaptype = SnapToBeatDiv24;
3532 } else if (choice == _("Beats/28")) {
3533 snaptype = SnapToBeatDiv28;
3534 } else if (choice == _("Beats/32")) {
3535 snaptype = SnapToBeatDiv32;
3536 } else if (choice == _("Beats")) {
3537 snaptype = SnapToBeat;
3538 } else if (choice == _("Bars")) {
3539 snaptype = SnapToBar;
3540 } else if (choice == _("Marks")) {
3541 snaptype = SnapToMark;
3542 } else if (choice == _("Region starts")) {
3543 snaptype = SnapToRegionStart;
3544 } else if (choice == _("Region ends")) {
3545 snaptype = SnapToRegionEnd;
3546 } else if (choice == _("Region bounds")) {
3547 snaptype = SnapToRegionBoundary;
3548 } else if (choice == _("Region syncs")) {
3549 snaptype = SnapToRegionSync;
3550 } else if (choice == _("CD Frames")) {
3551 snaptype = SnapToCDFrame;
3552 } else if (choice == _("Timecode Frames")) {
3553 snaptype = SnapToTimecodeFrame;
3554 } else if (choice == _("Timecode Seconds")) {
3555 snaptype = SnapToTimecodeSeconds;
3556 } else if (choice == _("Timecode Minutes")) {
3557 snaptype = SnapToTimecodeMinutes;
3558 } else if (choice == _("Seconds")) {
3559 snaptype = SnapToSeconds;
3560 } else if (choice == _("Minutes")) {
3561 snaptype = SnapToMinutes;
3564 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3566 ract->set_active ();
3571 Editor::snap_mode_selection_done ()
3573 string choice = snap_mode_selector.get_active_text();
3574 SnapMode mode = SnapNormal;
3576 if (choice == _("No Grid")) {
3578 } else if (choice == _("Grid")) {
3580 } else if (choice == _("Magnetic")) {
3581 mode = SnapMagnetic;
3584 RefPtr<RadioAction> ract = snap_mode_action (mode);
3587 ract->set_active (true);
3592 Editor::cycle_edit_point (bool with_marker)
3594 switch (_edit_point) {
3596 set_edit_point_preference (EditAtPlayhead);
3598 case EditAtPlayhead:
3600 set_edit_point_preference (EditAtSelectedMarker);
3602 set_edit_point_preference (EditAtMouse);
3605 case EditAtSelectedMarker:
3606 set_edit_point_preference (EditAtMouse);
3612 Editor::edit_point_selection_done ()
3614 string choice = edit_point_selector.get_active_text();
3615 EditPoint ep = EditAtSelectedMarker;
3617 if (choice == _("Marker")) {
3618 set_edit_point_preference (EditAtSelectedMarker);
3619 } else if (choice == _("Playhead")) {
3620 set_edit_point_preference (EditAtPlayhead);
3622 set_edit_point_preference (EditAtMouse);
3625 RefPtr<RadioAction> ract = edit_point_action (ep);
3628 ract->set_active (true);
3633 Editor::zoom_focus_selection_done ()
3635 string choice = zoom_focus_selector.get_active_text();
3636 ZoomFocus focus_type = ZoomFocusLeft;
3638 if (choice == _("Left")) {
3639 focus_type = ZoomFocusLeft;
3640 } else if (choice == _("Right")) {
3641 focus_type = ZoomFocusRight;
3642 } else if (choice == _("Center")) {
3643 focus_type = ZoomFocusCenter;
3644 } else if (choice == _("Playhead")) {
3645 focus_type = ZoomFocusPlayhead;
3646 } else if (choice == _("Mouse")) {
3647 focus_type = ZoomFocusMouse;
3648 } else if (choice == _("Edit point")) {
3649 focus_type = ZoomFocusEdit;
3652 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3655 ract->set_active ();
3660 Editor::edit_controls_button_release (GdkEventButton* ev)
3662 if (Keyboard::is_context_menu_event (ev)) {
3663 ARDOUR_UI::instance()->add_route (this);
3669 Editor::mouse_select_button_release (GdkEventButton* ev)
3671 /* this handles just right-clicks */
3673 if (ev->button != 3) {
3681 Editor::set_zoom_focus (ZoomFocus f)
3683 string str = zoom_focus_strings[(int)f];
3685 if (str != zoom_focus_selector.get_active_text()) {
3686 zoom_focus_selector.set_active_text (str);
3689 if (zoom_focus != f) {
3692 ZoomFocusChanged (); /* EMIT_SIGNAL */
3699 Editor::ensure_float (Window& win)
3701 win.set_transient_for (*this);
3705 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3707 /* recover or initialize pane positions. do this here rather than earlier because
3708 we don't want the positions to change the child allocations, which they seem to do.
3714 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3726 width = default_width;
3727 height = default_height;
3729 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3731 prop = geometry->property ("x-size");
3733 width = atoi (prop->value());
3735 prop = geometry->property ("y-size");
3737 height = atoi (prop->value());
3741 if (which == static_cast<Paned*> (&edit_pane)) {
3743 if (done & Horizontal) {
3747 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3748 /* initial allocation is 90% to canvas, 10% to notebook */
3749 pos = (int) floor (alloc.get_width() * 0.90f);
3750 snprintf (buf, sizeof(buf), "%d", pos);
3752 pos = atoi (prop->value());
3755 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3756 edit_pane.set_position (pos);
3757 pre_maximal_horizontal_pane_position = pos;
3760 done = (Pane) (done | Horizontal);
3762 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3764 if (done & Vertical) {
3768 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3769 /* initial allocation is 90% to canvas, 10% to summary */
3770 pos = (int) floor (alloc.get_height() * 0.90f);
3771 snprintf (buf, sizeof(buf), "%d", pos);
3773 pos = atoi (prop->value());
3776 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3777 editor_summary_pane.set_position (pos);
3778 pre_maximal_vertical_pane_position = pos;
3781 done = (Pane) (done | Vertical);
3786 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3788 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3789 top_hbox.remove (toolbar_frame);
3794 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3796 if (toolbar_frame.get_parent() == 0) {
3797 top_hbox.pack_end (toolbar_frame);
3802 Editor::set_show_measures (bool yn)
3804 if (_show_measures != yn) {
3807 if ((_show_measures = yn) == true) {
3809 tempo_lines->show();
3817 Editor::toggle_follow_playhead ()
3819 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3821 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3822 set_follow_playhead (tact->get_active());
3827 Editor::set_follow_playhead (bool yn)
3829 if (_follow_playhead != yn) {
3830 if ((_follow_playhead = yn) == true) {
3832 reset_x_origin_to_follow_playhead ();
3839 Editor::toggle_stationary_playhead ()
3841 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3843 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3844 set_stationary_playhead (tact->get_active());
3849 Editor::set_stationary_playhead (bool yn)
3851 if (_stationary_playhead != yn) {
3852 if ((_stationary_playhead = yn) == true) {
3854 // FIXME need a 3.0 equivalent of this 2.X call
3855 // update_current_screen ();
3862 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3864 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3866 xfade->set_active (!xfade->active());
3871 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3873 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3875 xfade->set_follow_overlap (!xfade->following_overlap());
3880 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3882 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3888 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3892 switch (cew.run ()) {
3893 case RESPONSE_ACCEPT:
3900 PropertyChange all_crossfade_properties;
3901 all_crossfade_properties.add (ARDOUR::Properties::active);
3902 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3903 xfade->PropertyChanged (all_crossfade_properties);
3907 Editor::playlist_selector () const
3909 return *_playlist_selector;
3913 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3917 switch (_snap_type) {
3922 case SnapToBeatDiv32:
3925 case SnapToBeatDiv28:
3928 case SnapToBeatDiv24:
3931 case SnapToBeatDiv20:
3934 case SnapToBeatDiv16:
3937 case SnapToBeatDiv14:
3940 case SnapToBeatDiv12:
3943 case SnapToBeatDiv10:
3946 case SnapToBeatDiv8:
3949 case SnapToBeatDiv7:
3952 case SnapToBeatDiv6:
3955 case SnapToBeatDiv5:
3958 case SnapToBeatDiv4:
3961 case SnapToBeatDiv3:
3964 case SnapToBeatDiv2:
3970 return _session->tempo_map().meter_at (position).beats_per_bar();
3975 case SnapToTimecodeFrame:
3976 case SnapToTimecodeSeconds:
3977 case SnapToTimecodeMinutes:
3980 case SnapToRegionStart:
3981 case SnapToRegionEnd:
3982 case SnapToRegionSync:
3983 case SnapToRegionBoundary:
3993 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3997 ret = nudge_clock.current_duration (pos);
3998 next = ret + 1; /* XXXX fix me */
4004 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4006 ArdourDialog dialog (_("Playlist Deletion"));
4007 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4008 "If left alone, no audio files used by it will be cleaned.\n"
4009 "If deleted, audio files used by it alone by will cleaned."),
4012 dialog.set_position (WIN_POS_CENTER);
4013 dialog.get_vbox()->pack_start (label);
4017 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
4018 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
4019 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4021 switch (dialog.run ()) {
4022 case RESPONSE_ACCEPT:
4023 /* delete the playlist */
4027 case RESPONSE_REJECT:
4028 /* keep the playlist */
4040 Editor::audio_region_selection_covers (framepos_t where)
4042 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4043 if ((*a)->region()->covers (where)) {
4052 Editor::prepare_for_cleanup ()
4054 cut_buffer->clear_regions ();
4055 cut_buffer->clear_playlists ();
4057 selection->clear_regions ();
4058 selection->clear_playlists ();
4060 _regions->suspend_redisplay ();
4064 Editor::finish_cleanup ()
4066 _regions->resume_redisplay ();
4070 Editor::transport_loop_location()
4073 return _session->locations()->auto_loop_location();
4080 Editor::transport_punch_location()
4083 return _session->locations()->auto_punch_location();
4090 Editor::control_layout_scroll (GdkEventScroll* ev)
4092 if (Keyboard::some_magic_widget_has_focus()) {
4096 switch (ev->direction) {
4098 scroll_tracks_up_line ();
4102 case GDK_SCROLL_DOWN:
4103 scroll_tracks_down_line ();
4107 /* no left/right handling yet */
4115 Editor::session_state_saved (string)
4118 _snapshots->redisplay ();
4122 Editor::maximise_editing_space ()
4124 _mouse_mode_tearoff->set_visible (false);
4125 _tools_tearoff->set_visible (false);
4126 _zoom_tearoff->set_visible (false);
4128 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4129 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4130 pre_maximal_editor_width = this->get_width ();
4131 pre_maximal_editor_height = this->get_height ();
4133 if (post_maximal_horizontal_pane_position == 0) {
4134 post_maximal_horizontal_pane_position = edit_pane.get_width();
4137 if (post_maximal_vertical_pane_position == 0) {
4138 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4143 if (post_maximal_editor_width) {
4144 edit_pane.set_position (post_maximal_horizontal_pane_position -
4145 abs(post_maximal_editor_width - pre_maximal_editor_width));
4147 edit_pane.set_position (post_maximal_horizontal_pane_position);
4150 if (post_maximal_editor_height) {
4151 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4152 abs(post_maximal_editor_height - pre_maximal_editor_height));
4154 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4157 if (Config->get_keep_tearoffs()) {
4158 _mouse_mode_tearoff->set_visible (true);
4159 _tools_tearoff->set_visible (true);
4160 _zoom_tearoff->set_visible (true);
4166 Editor::restore_editing_space ()
4168 // user changed width/height of panes during fullscreen
4170 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4171 post_maximal_horizontal_pane_position = edit_pane.get_position();
4174 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4175 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4180 _mouse_mode_tearoff->set_visible (true);
4181 _tools_tearoff->set_visible (true);
4182 _zoom_tearoff->set_visible (true);
4183 post_maximal_editor_width = this->get_width();
4184 post_maximal_editor_height = this->get_height();
4186 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4187 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4191 * Make new playlists for a given track and also any others that belong
4192 * to the same active route group with the `edit' property.
4197 Editor::new_playlists (TimeAxisView* v)
4199 begin_reversible_command (_("new playlists"));
4200 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4201 _session->playlists->get (playlists);
4202 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4203 commit_reversible_command ();
4207 * Use a copy of the current playlist for a given track and also any others that belong
4208 * to the same active route group with the `edit' property.
4213 Editor::copy_playlists (TimeAxisView* v)
4215 begin_reversible_command (_("copy playlists"));
4216 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4217 _session->playlists->get (playlists);
4218 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4219 commit_reversible_command ();
4222 /** Clear the current playlist for a given track and also any others that belong
4223 * to the same active route group with the `edit' property.
4228 Editor::clear_playlists (TimeAxisView* v)
4230 begin_reversible_command (_("clear playlists"));
4231 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4232 _session->playlists->get (playlists);
4233 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4234 commit_reversible_command ();
4238 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4240 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4244 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4246 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4250 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4252 atv.clear_playlist ();
4256 Editor::on_key_press_event (GdkEventKey* ev)
4258 return key_press_focus_accelerator_handler (*this, ev);
4262 Editor::on_key_release_event (GdkEventKey* ev)
4264 return Gtk::Window::on_key_release_event (ev);
4265 // return key_press_focus_accelerator_handler (*this, ev);
4268 /** Queue up a change to the viewport x origin.
4269 * @param frame New x origin.
4272 Editor::reset_x_origin (framepos_t frame)
4274 queue_visual_change (frame);
4278 Editor::reset_y_origin (double y)
4280 queue_visual_change_y (y);
4284 Editor::reset_zoom (double fpu)
4286 queue_visual_change (fpu);
4290 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4292 reset_x_origin (frame);
4295 if (!no_save_visual) {
4296 undo_visual_stack.push_back (current_visual_state(false));
4300 Editor::VisualState*
4301 Editor::current_visual_state (bool with_tracks)
4303 VisualState* vs = new VisualState;
4304 vs->y_position = vertical_adjustment.get_value();
4305 vs->frames_per_unit = frames_per_unit;
4306 vs->leftmost_frame = leftmost_frame;
4307 vs->zoom_focus = zoom_focus;
4310 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4311 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4319 Editor::undo_visual_state ()
4321 if (undo_visual_stack.empty()) {
4325 redo_visual_stack.push_back (current_visual_state());
4327 VisualState* vs = undo_visual_stack.back();
4328 undo_visual_stack.pop_back();
4329 use_visual_state (*vs);
4333 Editor::redo_visual_state ()
4335 if (redo_visual_stack.empty()) {
4339 undo_visual_stack.push_back (current_visual_state());
4341 VisualState* vs = redo_visual_stack.back();
4342 redo_visual_stack.pop_back();
4343 use_visual_state (*vs);
4347 Editor::swap_visual_state ()
4349 if (undo_visual_stack.empty()) {
4350 redo_visual_state ();
4352 undo_visual_state ();
4357 Editor::use_visual_state (VisualState& vs)
4359 no_save_visual = true;
4361 _routes->suspend_redisplay ();
4363 vertical_adjustment.set_value (vs.y_position);
4365 set_zoom_focus (vs.zoom_focus);
4366 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4368 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4369 TrackViewList::iterator t;
4371 /* check if the track still exists - it could have been deleted */
4373 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4374 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4379 if (!vs.track_states.empty()) {
4380 _routes->update_visibility ();
4383 _routes->resume_redisplay ();
4385 no_save_visual = false;
4389 Editor::set_frames_per_unit (double fpu)
4391 /* this is the core function that controls the zoom level of the canvas. it is called
4392 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4395 if (fpu == frames_per_unit) {
4404 /* don't allow zooms that fit more than the maximum number
4405 of frames into an 800 pixel wide space.
4408 if (max_framepos / fpu < 800.0) {
4413 tempo_lines->tempo_map_changed();
4415 frames_per_unit = fpu;
4420 Editor::post_zoom ()
4422 // convert fpu to frame count
4424 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4426 if (frames_per_unit != zoom_range_clock.current_duration()) {
4427 zoom_range_clock.set (frames);
4430 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4431 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4432 (*i)->reshow_selection (selection->time);
4436 ZoomChanged (); /* EMIT_SIGNAL */
4438 //reset_scrolling_region ();
4440 if (playhead_cursor) {
4441 playhead_cursor->set_position (playhead_cursor->current_frame);
4444 refresh_location_display();
4445 _summary->set_overlays_dirty ();
4447 update_marker_labels ();
4453 Editor::queue_visual_change (framepos_t where)
4455 pending_visual_change.add (VisualChange::TimeOrigin);
4456 pending_visual_change.time_origin = where;
4457 ensure_visual_change_idle_handler ();
4461 Editor::queue_visual_change (double fpu)
4463 pending_visual_change.add (VisualChange::ZoomLevel);
4464 pending_visual_change.frames_per_unit = fpu;
4466 ensure_visual_change_idle_handler ();
4470 Editor::queue_visual_change_y (double y)
4472 pending_visual_change.add (VisualChange::YOrigin);
4473 pending_visual_change.y_origin = y;
4475 ensure_visual_change_idle_handler ();
4479 Editor::ensure_visual_change_idle_handler ()
4481 if (pending_visual_change.idle_handler_id < 0) {
4482 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4487 Editor::_idle_visual_changer (void* arg)
4489 return static_cast<Editor*>(arg)->idle_visual_changer ();
4493 Editor::idle_visual_changer ()
4495 VisualChange::Type p = pending_visual_change.pending;
4496 pending_visual_change.pending = (VisualChange::Type) 0;
4498 double const last_time_origin = horizontal_position ();
4500 if (p & VisualChange::TimeOrigin) {
4501 /* This is a bit of a hack, but set_frames_per_unit
4502 below will (if called) end up with the
4503 CrossfadeViews looking at Editor::leftmost_frame,
4504 and if we're changing origin and zoom in the same
4505 operation it will be the wrong value unless we
4509 leftmost_frame = pending_visual_change.time_origin;
4512 if (p & VisualChange::ZoomLevel) {
4513 set_frames_per_unit (pending_visual_change.frames_per_unit);
4515 compute_fixed_ruler_scale ();
4516 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4517 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4518 update_tempo_based_rulers ();
4520 if (p & VisualChange::TimeOrigin) {
4521 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4523 if (p & VisualChange::YOrigin) {
4524 vertical_adjustment.set_value (pending_visual_change.y_origin);
4527 if (last_time_origin == horizontal_position ()) {
4528 /* changed signal not emitted */
4529 update_fixed_rulers ();
4530 redisplay_tempo (true);
4533 _summary->set_overlays_dirty ();
4535 pending_visual_change.idle_handler_id = -1;
4536 return 0; /* this is always a one-shot call */
4539 struct EditorOrderTimeAxisSorter {
4540 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4541 return a->order () < b->order ();
4546 Editor::sort_track_selection (TrackViewList* sel)
4548 EditorOrderTimeAxisSorter cmp;
4553 selection->tracks.sort (cmp);
4558 Editor::get_preferred_edit_position (bool ignore_playhead)
4561 framepos_t where = 0;
4562 EditPoint ep = _edit_point;
4564 if (entered_marker) {
4565 return entered_marker->position();
4568 if (ignore_playhead && ep == EditAtPlayhead) {
4569 ep = EditAtSelectedMarker;
4573 case EditAtPlayhead:
4574 where = _session->audible_frame();
4577 case EditAtSelectedMarker:
4578 if (!selection->markers.empty()) {
4580 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4583 where = loc->start();
4594 if (!mouse_frame (where, ignored)) {
4595 /* XXX not right but what can we do ? */
4606 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4608 if (!_session) return;
4610 begin_reversible_command (cmd);
4614 if ((tll = transport_loop_location()) == 0) {
4615 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4616 XMLNode &before = _session->locations()->get_state();
4617 _session->locations()->add (loc, true);
4618 _session->set_auto_loop_location (loc);
4619 XMLNode &after = _session->locations()->get_state();
4620 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4622 XMLNode &before = tll->get_state();
4623 tll->set_hidden (false, this);
4624 tll->set (start, end);
4625 XMLNode &after = tll->get_state();
4626 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4629 commit_reversible_command ();
4633 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4635 if (!_session) return;
4637 begin_reversible_command (cmd);
4641 if ((tpl = transport_punch_location()) == 0) {
4642 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4643 XMLNode &before = _session->locations()->get_state();
4644 _session->locations()->add (loc, true);
4645 _session->set_auto_loop_location (loc);
4646 XMLNode &after = _session->locations()->get_state();
4647 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4650 XMLNode &before = tpl->get_state();
4651 tpl->set_hidden (false, this);
4652 tpl->set (start, end);
4653 XMLNode &after = tpl->get_state();
4654 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4657 commit_reversible_command ();
4660 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4661 * @param rs List to which found regions are added.
4662 * @param where Time to look at.
4663 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4666 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4668 const TrackViewList* tracks;
4671 tracks = &track_views;
4676 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4677 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4679 boost::shared_ptr<Track> tr;
4680 boost::shared_ptr<Playlist> pl;
4682 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4684 Playlist::RegionList* regions = pl->regions_at (
4685 (framepos_t) floor ( (double)where * tr->speed()));
4687 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4688 RegionView* rv = rtv->view()->find_view (*i);
4701 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4703 const TrackViewList* tracks;
4706 tracks = &track_views;
4711 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4712 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4714 boost::shared_ptr<Track> tr;
4715 boost::shared_ptr<Playlist> pl;
4717 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4719 Playlist::RegionList* regions = pl->regions_touched (
4720 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4722 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4724 RegionView* rv = rtv->view()->find_view (*i);
4737 /** Get regions using the following conditions:
4738 * 1. If the edit point is `mouse':
4739 * if the mouse is over a selected region, or no region, return all selected regions.
4740 * if the mouse is over an unselected region, return just that region.
4741 * 2. For all other edit points:
4742 * return the selected regions AND those that are both under the edit position
4743 * AND on a selected track, or on a track which is in the same active edit-enabled route group
4744 * as a selected region.
4746 * The rationale here is that the mouse edit point is special in that its position describes
4747 * both a time and a track; the other edit modes only describe a time.
4749 * @param rs Returned region list.
4753 Editor::get_regions_from_selection_and_edit_point ()
4755 if (_edit_point == EditAtMouse) {
4756 if (entered_regionview == 0 || selection->regions.contains (entered_regionview)) {
4757 return selection->regions;
4760 rs.add (entered_regionview);
4765 /* We're using the edit point, but its not EditAtMouse */
4767 /* Start with selected regions */
4768 RegionSelection rs = selection->regions;
4770 TrackViewList tracks = selection->tracks;
4772 /* Tracks is currently the set of selected tracks; add any other tracks that
4773 have regions that are in the same edit-activated route group as one of
4776 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4778 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4779 if (g && g->is_active() && g->is_edit()) {
4780 tracks.add (axis_views_from_routes (g->route_list()));
4785 if (!tracks.empty()) {
4786 /* now find regions that are at the edit position on those tracks */
4787 framepos_t const where = get_preferred_edit_position ();
4788 get_regions_at (rs, where, tracks);
4796 Editor::get_regions_from_selection_and_entered ()
4798 RegionSelection rs = selection->regions;
4800 if (rs.empty() && entered_regionview) {
4801 rs.add (entered_regionview);
4808 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4810 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4812 RouteTimeAxisView* tatv;
4814 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4816 boost::shared_ptr<Playlist> pl;
4817 vector<boost::shared_ptr<Region> > results;
4819 boost::shared_ptr<Track> tr;
4821 if ((tr = tatv->track()) == 0) {
4826 if ((pl = (tr->playlist())) != 0) {
4827 pl->get_region_list_equivalent_regions (region, results);
4830 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4831 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4832 regions.push_back (marv);
4841 Editor::show_rhythm_ferret ()
4843 if (rhythm_ferret == 0) {
4844 rhythm_ferret = new RhythmFerret(*this);
4847 rhythm_ferret->set_session (_session);
4848 rhythm_ferret->show ();
4849 rhythm_ferret->present ();
4853 Editor::first_idle ()
4855 MessageDialog* dialog = 0;
4857 if (track_views.size() > 1) {
4858 dialog = new MessageDialog (*this,
4859 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4864 ARDOUR_UI::instance()->flush_pending ();
4867 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4871 // first idle adds route children (automation tracks), so we need to redisplay here
4872 _routes->redisplay ();
4880 Editor::_idle_resize (gpointer arg)
4882 return ((Editor*)arg)->idle_resize ();
4886 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4888 if (resize_idle_id < 0) {
4889 resize_idle_id = g_idle_add (_idle_resize, this);
4890 _pending_resize_amount = 0;
4893 /* make a note of the smallest resulting height, so that we can clamp the
4894 lower limit at TimeAxisView::hSmall */
4896 int32_t min_resulting = INT32_MAX;
4898 _pending_resize_amount += h;
4899 _pending_resize_view = view;
4901 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4903 if (selection->tracks.contains (_pending_resize_view)) {
4904 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4905 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4909 if (min_resulting < 0) {
4914 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4915 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4919 /** Handle pending resizing of tracks */
4921 Editor::idle_resize ()
4923 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4925 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4926 selection->tracks.contains (_pending_resize_view)) {
4928 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4929 if (*i != _pending_resize_view) {
4930 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4935 _pending_resize_amount = 0;
4937 _group_tabs->set_dirty ();
4938 resize_idle_id = -1;
4946 ENSURE_GUI_THREAD (*this, &Editor::located);
4948 playhead_cursor->set_position (_session->audible_frame ());
4949 if (_follow_playhead && !_pending_initial_locate) {
4950 reset_x_origin_to_follow_playhead ();
4953 _pending_locate_request = false;
4954 _pending_initial_locate = false;
4958 Editor::region_view_added (RegionView *)
4960 _summary->set_dirty ();
4964 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4966 TrackViewList::const_iterator j = track_views.begin ();
4967 while (j != track_views.end()) {
4968 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4969 if (rtv && rtv->route() == r) {
4980 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4984 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4985 TimeAxisView* tv = axis_view_from_route (*i);
4996 Editor::handle_new_route (RouteList& routes)
4998 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5000 RouteTimeAxisView *rtv;
5001 list<RouteTimeAxisView*> new_views;
5003 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5004 boost::shared_ptr<Route> route = (*x);
5006 if (route->is_hidden() || route->is_monitor()) {
5010 DataType dt = route->input()->default_type();
5012 if (dt == ARDOUR::DataType::AUDIO) {
5013 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
5014 } else if (dt == ARDOUR::DataType::MIDI) {
5015 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
5017 throw unknown_type();
5020 new_views.push_back (rtv);
5021 track_views.push_back (rtv);
5023 rtv->effective_gain_display ();
5025 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5028 _routes->routes_added (new_views);
5030 if (show_editor_mixer_when_tracks_arrive) {
5031 show_editor_mixer (true);
5034 editor_list_button.set_sensitive (true);
5036 _summary->set_dirty ();
5040 Editor::timeaxisview_deleted (TimeAxisView *tv)
5042 if (_session && _session->deletion_in_progress()) {
5043 /* the situation is under control */
5047 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5049 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5051 _routes->route_removed (tv);
5053 if (tv == entered_track) {
5057 TimeAxisView::Children c = tv->get_child_list ();
5058 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5059 if (entered_track == i->get()) {
5064 /* remove it from the list of track views */
5066 TrackViewList::iterator i;
5068 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5069 i = track_views.erase (i);
5072 /* update whatever the current mixer strip is displaying, if revelant */
5074 boost::shared_ptr<Route> route;
5077 route = rtav->route ();
5080 if (current_mixer_strip && current_mixer_strip->route() == route) {
5082 TimeAxisView* next_tv;
5084 if (track_views.empty()) {
5086 } else if (i == track_views.end()) {
5087 next_tv = track_views.front();
5094 set_selected_mixer_strip (*next_tv);
5096 /* make the editor mixer strip go away setting the
5097 * button to inactive (which also unticks the menu option)
5100 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5106 Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/)
5108 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5110 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5111 // this will hide the mixer strip
5112 set_selected_mixer_strip (*tv);
5115 _routes->hide_track_in_display (*tv);
5119 Editor::sync_track_view_list_and_routes ()
5121 track_views = TrackViewList (_routes->views ());
5123 _summary->set_dirty ();
5124 _group_tabs->set_dirty ();
5126 return false; // do not call again (until needed)
5130 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5132 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5137 /** Find a RouteTimeAxisView by the ID of its route */
5139 Editor::get_route_view_by_route_id (PBD::ID& id) const
5141 RouteTimeAxisView* v;
5143 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5144 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5145 if(v->route()->id() == id) {
5155 Editor::fit_route_group (RouteGroup *g)
5157 TrackViewList ts = axis_views_from_routes (g->route_list ());
5162 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5164 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5167 _session->cancel_audition ();
5171 if (_session->is_auditioning()) {
5172 _session->cancel_audition ();
5173 if (r == last_audition_region) {
5178 _session->audition_region (r);
5179 last_audition_region = r;
5184 Editor::hide_a_region (boost::shared_ptr<Region> r)
5186 r->set_hidden (true);
5190 Editor::show_a_region (boost::shared_ptr<Region> r)
5192 r->set_hidden (false);
5196 Editor::audition_region_from_region_list ()
5198 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5202 Editor::hide_region_from_region_list ()
5204 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5208 Editor::show_region_in_region_list ()
5210 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5214 Editor::step_edit_status_change (bool yn)
5217 start_step_editing ();
5219 stop_step_editing ();
5224 Editor::start_step_editing ()
5226 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5230 Editor::stop_step_editing ()
5232 step_edit_connection.disconnect ();
5236 Editor::check_step_edit ()
5238 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5239 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5241 mtv->check_step_edit ();
5245 return true; // do it again, till we stop
5249 Editor::horizontal_scroll_left_press ()
5251 ++_scroll_callbacks;
5253 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5254 /* delay the first auto-repeat */
5258 double x = leftmost_position() - current_page_frames() / 5;
5265 /* do hacky auto-repeat */
5266 if (!_scroll_connection.connected ()) {
5267 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
5268 _scroll_callbacks = 0;
5275 Editor::horizontal_scroll_left_release ()
5277 _scroll_connection.disconnect ();
5281 Editor::horizontal_scroll_right_press ()
5283 ++_scroll_callbacks;
5285 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5286 /* delay the first auto-repeat */
5290 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5292 /* do hacky auto-repeat */
5293 if (!_scroll_connection.connected ()) {
5294 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
5295 _scroll_callbacks = 0;
5302 Editor::horizontal_scroll_right_release ()
5304 _scroll_connection.disconnect ();
5307 /** Queue a change for the Editor viewport x origin to follow the playhead */
5309 Editor::reset_x_origin_to_follow_playhead ()
5311 framepos_t const frame = playhead_cursor->current_frame;
5313 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5315 if (_session->transport_speed() < 0) {
5317 if (frame > (current_page_frames() / 2)) {
5318 center_screen (frame-(current_page_frames()/2));
5320 center_screen (current_page_frames()/2);
5325 if (frame < leftmost_frame) {
5328 if (_session->transport_rolling()) {
5329 /* rolling; end up with the playhead at the right of the page */
5330 l = frame - current_page_frames ();
5332 /* not rolling: end up with the playhead 3/4 of the way along the page */
5333 l = frame - (3 * current_page_frames() / 4);
5340 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5343 if (_session->transport_rolling()) {
5344 /* rolling: end up with the playhead on the left of the page */
5345 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5347 /* not rolling: end up with the playhead 1/4 of the way along the page */
5348 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5356 Editor::super_rapid_screen_update ()
5358 if (!_session || !_session->engine().running()) {
5362 /* METERING / MIXER STRIPS */
5364 /* update track meters, if required */
5365 if (is_mapped() && meters_running) {
5366 RouteTimeAxisView* rtv;
5367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5368 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5369 rtv->fast_update ();
5374 /* and any current mixer strip */
5375 if (current_mixer_strip) {
5376 current_mixer_strip->fast_update ();
5379 /* PLAYHEAD AND VIEWPORT */
5381 framepos_t const frame = _session->audible_frame();
5383 /* There are a few reasons why we might not update the playhead / viewport stuff:
5385 * 1. we don't update things when there's a pending locate request, otherwise
5386 * when the editor requests a locate there is a chance that this method
5387 * will move the playhead before the locate request is processed, causing
5389 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5390 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5393 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5395 last_update_frame = frame;
5397 if (!_dragging_playhead) {
5398 playhead_cursor->set_position (frame);
5401 if (!_stationary_playhead) {
5403 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5404 reset_x_origin_to_follow_playhead ();
5409 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5413 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5414 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5415 if (target <= 0.0) {
5418 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5419 target = (target * 0.15) + (current * 0.85);
5425 set_horizontal_position (current);
5434 Editor::session_going_away ()
5436 _have_idled = false;
5438 _session_connections.drop_connections ();
5440 super_rapid_screen_update_connection.disconnect ();
5442 selection->clear ();
5443 cut_buffer->clear ();
5445 clicked_regionview = 0;
5446 clicked_axisview = 0;
5447 clicked_routeview = 0;
5448 clicked_crossfadeview = 0;
5449 entered_regionview = 0;
5451 last_update_frame = 0;
5454 playhead_cursor->canvas_item.hide ();
5456 /* rip everything out of the list displays */
5460 _route_groups->clear ();
5462 /* do this first so that deleting a track doesn't reset cms to null
5463 and thus cause a leak.
5466 if (current_mixer_strip) {
5467 if (current_mixer_strip->get_parent() != 0) {
5468 global_hpacker.remove (*current_mixer_strip);
5470 delete current_mixer_strip;
5471 current_mixer_strip = 0;
5474 /* delete all trackviews */
5476 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5479 track_views.clear ();
5481 zoom_range_clock.set_session (0);
5482 nudge_clock.set_session (0);
5484 editor_list_button.set_active(false);
5485 editor_list_button.set_sensitive(false);
5487 /* clear tempo/meter rulers */
5488 remove_metric_marks ();
5490 clear_marker_display ();
5492 delete current_bbt_points;
5493 current_bbt_points = 0;
5495 /* get rid of any existing editor mixer strip */
5497 WindowTitle title(Glib::get_application_name());
5498 title += _("Editor");
5500 set_title (title.get_string());
5502 SessionHandlePtr::session_going_away ();
5507 Editor::show_editor_list (bool yn)
5510 the_notebook.show();
5512 the_notebook.hide();
5517 Editor::change_region_layering_order ()
5519 framepos_t const position = get_preferred_edit_position ();
5521 if (!clicked_routeview) {
5522 if (layering_order_editor) {
5523 layering_order_editor->hide ();
5528 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5534 boost::shared_ptr<Playlist> pl = track->playlist();
5540 if (layering_order_editor == 0) {
5541 layering_order_editor = new RegionLayeringOrderEditor(*this);
5544 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5545 layering_order_editor->maybe_present ();
5549 Editor::update_region_layering_order_editor ()
5551 if (layering_order_editor && layering_order_editor->is_visible ()) {
5552 change_region_layering_order ();
5557 Editor::setup_fade_images ()
5559 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5560 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5561 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5562 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5563 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5565 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5566 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5567 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5568 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5569 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5573 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5575 Editor::action_menu_item (std::string const & name)
5577 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5580 return *manage (a->create_menu_item ());