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;
757 setup_fade_images ();
763 if(image_socket_listener) {
764 if(image_socket_listener->is_connected())
766 image_socket_listener->close_connection() ;
769 delete image_socket_listener ;
770 image_socket_listener = 0 ;
775 delete _route_groups;
781 Editor::add_toplevel_controls (Container& cont)
783 vpacker.pack_start (cont, false, false);
788 Editor::catch_vanishing_regionview (RegionView *rv)
790 /* note: the selection will take care of the vanishing
791 audioregionview by itself.
794 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
798 if (clicked_regionview == rv) {
799 clicked_regionview = 0;
802 if (entered_regionview == rv) {
803 set_entered_regionview (0);
806 if (!_all_region_actions_sensitized) {
807 sensitize_all_region_actions (true);
812 Editor::set_entered_regionview (RegionView* rv)
814 if (rv == entered_regionview) {
818 if (entered_regionview) {
819 entered_regionview->exited ();
822 if ((entered_regionview = rv) != 0) {
823 entered_regionview->entered (internal_editing ());
826 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
827 /* This RegionView entry might have changed what region actions
828 are allowed, so sensitize them all in case a key is pressed.
830 sensitize_all_region_actions (true);
835 Editor::set_entered_track (TimeAxisView* tav)
838 entered_track->exited ();
841 if ((entered_track = tav) != 0) {
842 entered_track->entered ();
847 Editor::show_window ()
849 if (! is_visible ()) {
852 /* re-hide editor list if necessary */
853 editor_list_button_toggled ();
855 /* re-hide summary widget if necessary */
856 parameter_changed ("show-summary");
858 parameter_changed ("show-edit-group-tabs");
860 /* now reset all audio_time_axis heights, because widgets might need
866 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
867 tv = (static_cast<TimeAxisView*>(*i));
876 Editor::instant_save ()
878 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
883 _session->add_instant_xml(get_state());
885 Config->add_instant_xml(get_state());
890 Editor::zoom_adjustment_changed ()
896 double fpu = zoom_range_clock.current_duration() / _canvas_width;
900 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
901 } else if (fpu > _session->current_end_frame() / _canvas_width) {
902 fpu = _session->current_end_frame() / _canvas_width;
903 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
910 Editor::control_scroll (float fraction)
912 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
918 double step = fraction * current_page_frames();
921 _control_scroll_target is an optional<T>
923 it acts like a pointer to an framepos_t, with
924 a operator conversion to boolean to check
925 that it has a value could possibly use
926 playhead_cursor->current_frame to store the
927 value and a boolean in the class to know
928 when it's out of date
931 if (!_control_scroll_target) {
932 _control_scroll_target = _session->transport_frame();
933 _dragging_playhead = true;
936 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
937 *_control_scroll_target = 0;
938 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
939 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
941 *_control_scroll_target += (framepos_t) floor (step);
944 /* move visuals, we'll catch up with it later */
946 playhead_cursor->set_position (*_control_scroll_target);
947 UpdateAllTransportClocks (*_control_scroll_target);
949 if (*_control_scroll_target > (current_page_frames() / 2)) {
950 /* try to center PH in window */
951 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
957 Now we do a timeout to actually bring the session to the right place
958 according to the playhead. This is to avoid reading disk buffers on every
959 call to control_scroll, which is driven by ScrollTimeline and therefore
960 probably by a control surface wheel which can generate lots of events.
962 /* cancel the existing timeout */
964 control_scroll_connection.disconnect ();
966 /* add the next timeout */
968 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
972 Editor::deferred_control_scroll (framepos_t /*target*/)
974 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
975 // reset for next stream
976 _control_scroll_target = boost::none;
977 _dragging_playhead = false;
982 Editor::access_action (std::string action_group, std::string action_item)
988 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
991 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
999 Editor::on_realize ()
1001 Window::on_realize ();
1006 Editor::map_position_change (framepos_t frame)
1008 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1010 if (_session == 0) {
1014 if (_follow_playhead) {
1015 center_screen (frame);
1018 playhead_cursor->set_position (frame);
1022 Editor::center_screen (framepos_t frame)
1024 double page = _canvas_width * frames_per_unit;
1026 /* if we're off the page, then scroll.
1029 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1030 center_screen_internal (frame, page);
1035 Editor::center_screen_internal (framepos_t frame, float page)
1040 frame -= (framepos_t) page;
1045 reset_x_origin (frame);
1050 Editor::update_title ()
1052 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1055 bool dirty = _session->dirty();
1057 string session_name;
1059 if (_session->snap_name() != _session->name()) {
1060 session_name = _session->snap_name();
1062 session_name = _session->name();
1066 session_name = "*" + session_name;
1069 WindowTitle title(session_name);
1070 title += Glib::get_application_name();
1071 set_title (title.get_string());
1076 Editor::set_session (Session *t)
1078 SessionHandlePtr::set_session (t);
1084 zoom_range_clock.set_session (_session);
1085 _playlist_selector->set_session (_session);
1086 nudge_clock.set_session (_session);
1087 _summary->set_session (_session);
1088 _group_tabs->set_session (_session);
1089 _route_groups->set_session (_session);
1090 _regions->set_session (_session);
1091 _snapshots->set_session (_session);
1092 _routes->set_session (_session);
1093 _locations->set_session (_session);
1095 if (rhythm_ferret) {
1096 rhythm_ferret->set_session (_session);
1099 if (analysis_window) {
1100 analysis_window->set_session (_session);
1104 sfbrowser->set_session (_session);
1107 compute_fixed_ruler_scale ();
1109 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1110 set_state (*node, Stateful::loading_state_version);
1112 /* catch up with the playhead */
1114 _session->request_locate (playhead_cursor->current_frame);
1115 _pending_initial_locate = true;
1119 /* These signals can all be emitted by a non-GUI thread. Therefore the
1120 handlers for them must not attempt to directly interact with the GUI,
1121 but use Gtkmm2ext::UI::instance()->call_slot();
1124 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1125 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1126 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1127 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1128 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1129 _session->TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_just_timecode, this), gui_context());
1130 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1131 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1132 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1133 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1134 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1135 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1136 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1137 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1138 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1140 if (Profile->get_sae()) {
1145 nframes_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1146 nudge_clock.set_mode(AudioClock::BBT);
1147 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1150 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1153 playhead_cursor->canvas_item.show ();
1155 Location* loc = _session->locations()->auto_loop_location();
1157 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1158 if (loc->start() == loc->end()) {
1159 loc->set_end (loc->start() + 1);
1161 _session->locations()->add (loc, false);
1162 _session->set_auto_loop_location (loc);
1165 loc->set_name (_("Loop"));
1168 loc = _session->locations()->auto_punch_location();
1170 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1171 if (loc->start() == loc->end()) {
1172 loc->set_end (loc->start() + 1);
1174 _session->locations()->add (loc, false);
1175 _session->set_auto_punch_location (loc);
1178 loc->set_name (_("Punch"));
1181 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1182 Config->map_parameters (pc);
1183 _session->config.map_parameters (pc);
1185 refresh_location_display ();
1187 restore_ruler_visibility ();
1188 //tempo_map_changed (PropertyChange (0));
1189 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1191 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1192 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1195 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1196 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1199 switch (_snap_type) {
1200 case SnapToRegionStart:
1201 case SnapToRegionEnd:
1202 case SnapToRegionSync:
1203 case SnapToRegionBoundary:
1204 build_region_boundary_cache ();
1211 /* register for undo history */
1212 _session->register_with_memento_command_factory(_id, this);
1214 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1216 start_updating_meters ();
1220 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1222 if (a->get_name() == "RegionMenu") {
1223 /* When the main menu's region menu is opened, we setup the actions so that they look right
1224 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1225 so we resensitize all region actions when the entered regionview or the region selection
1226 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1227 happens after the region context menu is opened. So we set a flag here, too.
1231 sensitize_the_right_region_actions ();
1232 _last_region_menu_was_main = true;
1237 Editor::build_cursors ()
1239 using namespace Gdk;
1242 Glib::RefPtr<Gdk::Pixbuf> zoom_in_cursor_pixbuf (::get_icon ("zoom_in_cursor"));
1243 zoom_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_in_cursor_pixbuf, 5, 5);
1247 Glib::RefPtr<Gdk::Pixbuf> zoom_out_cursor_pixbuf (::get_icon ("zoom_out_cursor"));
1248 zoom_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), zoom_out_cursor_pixbuf, 5, 5);
1251 Gdk::Color fbg ("#ffffff" );
1252 Gdk::Color ffg ("#000000" );
1255 RefPtr<Bitmap> source, mask;
1257 source = Bitmap::create (fader_cursor_bits, fader_cursor_width, fader_cursor_height);
1258 mask = Bitmap::create (fader_cursor_mask_bits, fader_cursor_width, fader_cursor_height);
1259 fader_cursor = new Gdk::Cursor (source, mask, ffg, fbg, fader_cursor_x_hot, fader_cursor_y_hot);
1263 RefPtr<Bitmap> source, mask;
1264 source = Bitmap::create (speaker_cursor_bits, speaker_cursor_width, speaker_cursor_height);
1265 mask = Bitmap::create (speaker_cursor_mask_bits, speaker_cursor_width, speaker_cursor_height);
1266 speaker_cursor = new Gdk::Cursor (source, mask, ffg, fbg, speaker_cursor_x_hot, speaker_cursor_y_hot);
1270 RefPtr<Bitmap> bits;
1271 char pix[4] = { 0, 0, 0, 0 };
1272 bits = Bitmap::create (pix, 2, 2);
1274 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1278 RefPtr<Bitmap> bits;
1279 char pix[4] = { 0, 0, 0, 0 };
1280 bits = Bitmap::create (pix, 2, 2);
1282 transparent_cursor = new Gdk::Cursor (bits, bits, c, c, 0, 0);
1286 Glib::RefPtr<Gdk::Pixbuf> grabber_pixbuf (::get_icon ("grabber"));
1287 grabber_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_pixbuf, 5, 0);
1291 Glib::RefPtr<Gdk::Pixbuf> grabber_note_pixbuf (::get_icon ("grabber_note"));
1292 grabber_note_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_note_pixbuf, 5, 10);
1296 Glib::RefPtr<Gdk::Pixbuf> grabber_edit_point_pixbuf (::get_icon ("grabber_edit_point"));
1297 grabber_edit_point_cursor = new Gdk::Cursor (Gdk::Display::get_default(), grabber_edit_point_pixbuf, 5, 17);
1300 cross_hair_cursor = new Gdk::Cursor (CROSSHAIR);
1301 trimmer_cursor = new Gdk::Cursor (SB_H_DOUBLE_ARROW);
1304 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_left_cursor"));
1305 left_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 5, 11);
1309 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("trim_right_cursor"));
1310 right_side_trim_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 23, 11);
1314 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_in_cursor"));
1315 fade_in_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 0, 0);
1319 Glib::RefPtr<Gdk::Pixbuf> apixbuf (::get_icon ("fade_out_cursor"));
1320 fade_out_cursor = new Gdk::Cursor (Gdk::Display::get_default(), apixbuf, 29, 0);
1324 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_left_cursor"));
1325 resize_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 10);
1329 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_left_cursor"));
1330 resize_top_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 3);
1334 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_cursor"));
1335 resize_top_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 10, 3);
1339 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_top_right_cursor"));
1340 resize_top_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 18, 3);
1344 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_right_cursor"));
1345 resize_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 24, 10);
1349 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_right_cursor"));
1350 resize_bottom_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 18, 18);
1354 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_cursor"));
1355 resize_bottom_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 10, 24);
1359 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("resize_bottom_left_cursor"));
1360 resize_bottom_left_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 3, 18);
1364 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("move_cursor"));
1365 move_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 11, 11);
1369 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("expand_left_right_cursor"));
1370 expand_left_right_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 11, 4);
1374 Glib::RefPtr<Gdk::Pixbuf> p (::get_icon ("expand_up_down_cursor"));
1375 expand_up_down_cursor = new Gdk::Cursor (Gdk::Display::get_default(), p, 4, 11);
1378 selector_cursor = new Gdk::Cursor (XTERM);
1379 time_fx_cursor = new Gdk::Cursor (SIZING);
1380 wait_cursor = new Gdk::Cursor (WATCH);
1381 timebar_cursor = new Gdk::Cursor(LEFT_PTR);
1382 midi_pencil_cursor = new Gdk::Cursor (PENCIL);
1383 midi_select_cursor = new Gdk::Cursor (CENTER_PTR);
1384 midi_resize_cursor = new Gdk::Cursor (SIZING);
1385 midi_erase_cursor = new Gdk::Cursor (DRAPED_BOX);
1386 up_down_cursor = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW);
1389 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1391 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1393 using namespace Menu_Helpers;
1394 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1397 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1401 MenuList& items (fade_context_menu.items());
1405 switch (item_type) {
1407 case FadeInHandleItem:
1408 if (arv->audio_region()->fade_in_active()) {
1409 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1411 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1414 items.push_back (SeparatorElem());
1416 if (Profile->get_sae()) {
1418 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1419 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1426 *_fade_in_images[FadeLinear],
1427 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1431 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1436 *_fade_in_images[FadeFast],
1437 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1440 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1445 *_fade_in_images[FadeLogB],
1446 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1449 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 *_fade_in_images[FadeLogA],
1455 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1458 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1463 *_fade_in_images[FadeSlow],
1464 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 case FadeOutHandleItem:
1474 if (arv->audio_region()->fade_out_active()) {
1475 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1477 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1480 items.push_back (SeparatorElem());
1482 if (Profile->get_sae()) {
1483 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1484 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1490 *_fade_out_images[FadeLinear],
1491 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1500 *_fade_out_images[FadeFast],
1501 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 *_fade_out_images[FadeLogB],
1510 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 *_fade_out_images[FadeLogA],
1519 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1522 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1527 *_fade_out_images[FadeSlow],
1528 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1531 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1537 fatal << _("programming error: ")
1538 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1543 fade_context_menu.popup (button, time);
1547 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1549 using namespace Menu_Helpers;
1550 Menu* (Editor::*build_menu_function)();
1553 switch (item_type) {
1555 case RegionViewName:
1556 case RegionViewNameHighlight:
1557 case LeftFrameHandle:
1558 case RightFrameHandle:
1559 if (with_selection) {
1560 build_menu_function = &Editor::build_track_selection_context_menu;
1562 build_menu_function = &Editor::build_track_region_context_menu;
1567 if (with_selection) {
1568 build_menu_function = &Editor::build_track_selection_context_menu;
1570 build_menu_function = &Editor::build_track_context_menu;
1574 case CrossfadeViewItem:
1575 build_menu_function = &Editor::build_track_crossfade_context_menu;
1579 if (clicked_routeview->track()) {
1580 build_menu_function = &Editor::build_track_context_menu;
1582 build_menu_function = &Editor::build_track_bus_context_menu;
1587 /* probably shouldn't happen but if it does, we don't care */
1591 menu = (this->*build_menu_function)();
1592 menu->set_name ("ArdourContextMenu");
1594 /* now handle specific situations */
1596 switch (item_type) {
1598 case RegionViewName:
1599 case RegionViewNameHighlight:
1600 case LeftFrameHandle:
1601 case RightFrameHandle:
1602 if (!with_selection) {
1603 if (region_edit_menu_split_item) {
1604 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1605 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1607 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1610 if (region_edit_menu_split_multichannel_item) {
1611 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1612 region_edit_menu_split_multichannel_item->set_sensitive (true);
1614 region_edit_menu_split_multichannel_item->set_sensitive (false);
1623 case CrossfadeViewItem:
1630 /* probably shouldn't happen but if it does, we don't care */
1634 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1636 /* Bounce to disk */
1638 using namespace Menu_Helpers;
1639 MenuList& edit_items = menu->items();
1641 edit_items.push_back (SeparatorElem());
1643 switch (clicked_routeview->audio_track()->freeze_state()) {
1644 case AudioTrack::NoFreeze:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1648 case AudioTrack::Frozen:
1649 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1652 case AudioTrack::UnFrozen:
1653 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1659 if (item_type == StreamItem && clicked_routeview) {
1660 clicked_routeview->build_underlay_menu(menu);
1663 /* When the region menu is opened, we setup the actions so that they look right
1666 sensitize_the_right_region_actions ();
1667 _last_region_menu_was_main = false;
1669 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1670 menu->popup (button, time);
1674 Editor::build_track_context_menu ()
1676 using namespace Menu_Helpers;
1678 MenuList& edit_items = track_context_menu.items();
1681 add_dstream_context_items (edit_items);
1682 return &track_context_menu;
1686 Editor::build_track_bus_context_menu ()
1688 using namespace Menu_Helpers;
1690 MenuList& edit_items = track_context_menu.items();
1693 add_bus_context_items (edit_items);
1694 return &track_context_menu;
1698 Editor::build_track_region_context_menu ()
1700 using namespace Menu_Helpers;
1701 MenuList& edit_items = track_region_context_menu.items();
1704 /* we've just cleared the track region context menu, so the menu that these
1705 two items were on will have disappeared; stop them dangling.
1707 region_edit_menu_split_item = 0;
1708 region_edit_menu_split_multichannel_item = 0;
1710 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1713 boost::shared_ptr<Track> tr;
1714 boost::shared_ptr<Playlist> pl;
1716 /* Don't offer a region submenu if we are in internal edit mode, as we don't select regions in this
1717 mode and so offering region context is somewhat confusing.
1719 if ((tr = rtv->track()) && ((pl = tr->playlist())) && !internal_editing()) {
1720 framepos_t const framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1721 uint32_t regions_at = pl->count_regions_at (framepos);
1722 add_region_context_items (edit_items, regions_at > 1);
1726 add_dstream_context_items (edit_items);
1728 return &track_region_context_menu;
1732 Editor::build_track_crossfade_context_menu ()
1734 using namespace Menu_Helpers;
1735 MenuList& edit_items = track_crossfade_context_menu.items();
1736 edit_items.clear ();
1738 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1741 boost::shared_ptr<Track> tr;
1742 boost::shared_ptr<Playlist> pl;
1743 boost::shared_ptr<AudioPlaylist> apl;
1745 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1747 AudioPlaylist::Crossfades xfades;
1749 apl->crossfades_at (get_preferred_edit_position (), xfades);
1751 bool many = xfades.size() > 1;
1753 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1754 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1757 framepos_t framepos = (framepos_t) floor ((double) get_preferred_edit_position() * tr->speed());
1758 uint32_t regions_at = pl->count_regions_at (framepos);
1759 add_region_context_items (edit_items, regions_at > 1);
1763 add_dstream_context_items (edit_items);
1765 return &track_crossfade_context_menu;
1769 Editor::analyze_region_selection ()
1771 if (analysis_window == 0) {
1772 analysis_window = new AnalysisWindow();
1775 analysis_window->set_session(_session);
1777 analysis_window->show_all();
1780 analysis_window->set_regionmode();
1781 analysis_window->analyze();
1783 analysis_window->present();
1787 Editor::analyze_range_selection()
1789 if (analysis_window == 0) {
1790 analysis_window = new AnalysisWindow();
1793 analysis_window->set_session(_session);
1795 analysis_window->show_all();
1798 analysis_window->set_rangemode();
1799 analysis_window->analyze();
1801 analysis_window->present();
1805 Editor::build_track_selection_context_menu ()
1807 using namespace Menu_Helpers;
1808 MenuList& edit_items = track_selection_context_menu.items();
1809 edit_items.clear ();
1811 add_selection_context_items (edit_items);
1812 // edit_items.push_back (SeparatorElem());
1813 // add_dstream_context_items (edit_items);
1815 return &track_selection_context_menu;
1818 /** Add context menu items relevant to crossfades.
1819 * @param edit_items List to add the items to.
1822 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1824 using namespace Menu_Helpers;
1825 Menu *xfade_menu = manage (new Menu);
1826 MenuList& items = xfade_menu->items();
1827 xfade_menu->set_name ("ArdourContextMenu");
1830 if (xfade->active()) {
1836 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1837 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1839 if (xfade->can_follow_overlap()) {
1841 if (xfade->following_overlap()) {
1842 str = _("Convert to Short");
1844 str = _("Convert to Full");
1847 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1851 str = xfade->out()->name();
1853 str += xfade->in()->name();
1855 str = _("Crossfade");
1858 edit_items.push_back (MenuElem (str, *xfade_menu));
1859 edit_items.push_back (SeparatorElem());
1863 Editor::xfade_edit_left_region ()
1865 if (clicked_crossfadeview) {
1866 clicked_crossfadeview->left_view.show_region_editor ();
1871 Editor::xfade_edit_right_region ()
1873 if (clicked_crossfadeview) {
1874 clicked_crossfadeview->right_view.show_region_editor ();
1879 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, bool multiple_regions_at_position)
1881 using namespace Menu_Helpers;
1883 /* OK, stick the region submenu at the top of the list, and then add
1887 /* we have to hack up the region name because "_" has a special
1888 meaning for menu titles.
1891 RegionSelection rs = get_regions_from_selection_and_entered ();
1893 string::size_type pos = 0;
1894 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1896 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1897 menu_item_name.replace (pos, 1, "__");
1901 if (_popup_region_menu_item == 0) {
1902 _popup_region_menu_item = new MenuItem (menu_item_name);
1903 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1904 _popup_region_menu_item->show ();
1906 _popup_region_menu_item->set_label (menu_item_name);
1909 edit_items.push_back (*_popup_region_menu_item);
1910 if (multiple_regions_at_position && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1911 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1913 edit_items.push_back (SeparatorElem());
1916 /** Add context menu items relevant to selection ranges.
1917 * @param edit_items List to add the items to.
1920 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1922 using namespace Menu_Helpers;
1924 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1925 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1927 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1930 if (!selection->regions.empty()) {
1931 edit_items.push_back (SeparatorElem());
1932 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)));
1933 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)));
1936 edit_items.push_back (SeparatorElem());
1937 edit_items.push_back (MenuElem (_("Convert to region in-place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1938 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1940 edit_items.push_back (SeparatorElem());
1941 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1943 edit_items.push_back (SeparatorElem());
1944 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1945 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1947 edit_items.push_back (SeparatorElem());
1948 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1950 edit_items.push_back (SeparatorElem());
1951 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1952 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1953 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1955 edit_items.push_back (SeparatorElem());
1956 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1957 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1958 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1959 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1960 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1965 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1967 using namespace Menu_Helpers;
1971 Menu *play_menu = manage (new Menu);
1972 MenuList& play_items = play_menu->items();
1973 play_menu->set_name ("ArdourContextMenu");
1975 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1976 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1977 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1978 play_items.push_back (SeparatorElem());
1979 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1981 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1985 Menu *select_menu = manage (new Menu);
1986 MenuList& select_items = select_menu->items();
1987 select_menu->set_name ("ArdourContextMenu");
1989 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1992 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1993 select_items.push_back (SeparatorElem());
1994 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1995 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1996 select_items.push_back (SeparatorElem());
1997 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1998 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1999 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2000 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2001 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2002 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2003 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2005 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2009 Menu *cutnpaste_menu = manage (new Menu);
2010 MenuList& cutnpaste_items = cutnpaste_menu->items();
2011 cutnpaste_menu->set_name ("ArdourContextMenu");
2013 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2014 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2015 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2017 cutnpaste_items.push_back (SeparatorElem());
2019 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2020 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2022 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2024 /* Adding new material */
2026 edit_items.push_back (SeparatorElem());
2027 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2028 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2032 Menu *nudge_menu = manage (new Menu());
2033 MenuList& nudge_items = nudge_menu->items();
2034 nudge_menu->set_name ("ArdourContextMenu");
2036 edit_items.push_back (SeparatorElem());
2037 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2038 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2039 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2040 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2042 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2046 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2048 using namespace Menu_Helpers;
2052 Menu *play_menu = manage (new Menu);
2053 MenuList& play_items = play_menu->items();
2054 play_menu->set_name ("ArdourContextMenu");
2056 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2057 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2058 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2062 Menu *select_menu = manage (new Menu);
2063 MenuList& select_items = select_menu->items();
2064 select_menu->set_name ("ArdourContextMenu");
2066 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2067 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2068 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2069 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2070 select_items.push_back (SeparatorElem());
2071 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2072 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2073 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2074 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2076 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2080 Menu *cutnpaste_menu = manage (new Menu);
2081 MenuList& cutnpaste_items = cutnpaste_menu->items();
2082 cutnpaste_menu->set_name ("ArdourContextMenu");
2084 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2085 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2086 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2088 Menu *nudge_menu = manage (new Menu());
2089 MenuList& nudge_items = nudge_menu->items();
2090 nudge_menu->set_name ("ArdourContextMenu");
2092 edit_items.push_back (SeparatorElem());
2093 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2094 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2095 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2096 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2098 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2102 Editor::snap_type() const
2108 Editor::snap_mode() const
2114 Editor::set_snap_to (SnapType st)
2116 unsigned int snap_ind = (unsigned int)st;
2120 if (snap_ind > snap_type_strings.size() - 1) {
2122 _snap_type = (SnapType)snap_ind;
2125 string str = snap_type_strings[snap_ind];
2127 if (str != snap_type_selector.get_active_text()) {
2128 snap_type_selector.set_active_text (str);
2133 switch (_snap_type) {
2134 case SnapToBeatDiv32:
2135 case SnapToBeatDiv28:
2136 case SnapToBeatDiv24:
2137 case SnapToBeatDiv20:
2138 case SnapToBeatDiv16:
2139 case SnapToBeatDiv14:
2140 case SnapToBeatDiv12:
2141 case SnapToBeatDiv10:
2142 case SnapToBeatDiv8:
2143 case SnapToBeatDiv7:
2144 case SnapToBeatDiv6:
2145 case SnapToBeatDiv5:
2146 case SnapToBeatDiv4:
2147 case SnapToBeatDiv3:
2148 case SnapToBeatDiv2:
2149 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2150 update_tempo_based_rulers ();
2153 case SnapToRegionStart:
2154 case SnapToRegionEnd:
2155 case SnapToRegionSync:
2156 case SnapToRegionBoundary:
2157 build_region_boundary_cache ();
2165 SnapChanged (); /* EMIT SIGNAL */
2169 Editor::set_snap_mode (SnapMode mode)
2172 string str = snap_mode_strings[(int)mode];
2174 if (str != snap_mode_selector.get_active_text ()) {
2175 snap_mode_selector.set_active_text (str);
2181 Editor::set_edit_point_preference (EditPoint ep, bool force)
2183 bool changed = (_edit_point != ep);
2186 string str = edit_point_strings[(int)ep];
2188 if (str != edit_point_selector.get_active_text ()) {
2189 edit_point_selector.set_active_text (str);
2192 set_canvas_cursor ();
2194 if (!force && !changed) {
2198 const char* action=NULL;
2200 switch (_edit_point) {
2201 case EditAtPlayhead:
2202 action = "edit-at-playhead";
2204 case EditAtSelectedMarker:
2205 action = "edit-at-marker";
2208 action = "edit-at-mouse";
2212 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2214 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2218 bool in_track_canvas;
2220 if (!mouse_frame (foo, in_track_canvas)) {
2221 in_track_canvas = false;
2224 reset_canvas_action_sensitivity (in_track_canvas);
2230 Editor::set_state (const XMLNode& node, int /*version*/)
2232 const XMLProperty* prop;
2234 int x, y, xoff, yoff;
2237 if ((prop = node.property ("id")) != 0) {
2238 _id = prop->value ();
2241 g.base_width = default_width;
2242 g.base_height = default_height;
2248 if ((geometry = find_named_node (node, "geometry")) != 0) {
2252 if ((prop = geometry->property("x_size")) == 0) {
2253 prop = geometry->property ("x-size");
2256 g.base_width = atoi(prop->value());
2258 if ((prop = geometry->property("y_size")) == 0) {
2259 prop = geometry->property ("y-size");
2262 g.base_height = atoi(prop->value());
2265 if ((prop = geometry->property ("x_pos")) == 0) {
2266 prop = geometry->property ("x-pos");
2269 x = atoi (prop->value());
2272 if ((prop = geometry->property ("y_pos")) == 0) {
2273 prop = geometry->property ("y-pos");
2276 y = atoi (prop->value());
2279 if ((prop = geometry->property ("x_off")) == 0) {
2280 prop = geometry->property ("x-off");
2283 xoff = atoi (prop->value());
2285 if ((prop = geometry->property ("y_off")) == 0) {
2286 prop = geometry->property ("y-off");
2289 yoff = atoi (prop->value());
2293 set_default_size (g.base_width, g.base_height);
2296 if (_session && (prop = node.property ("playhead"))) {
2298 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2299 playhead_cursor->set_position (pos);
2301 playhead_cursor->set_position (0);
2304 if ((prop = node.property ("mixer-width"))) {
2305 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2308 if ((prop = node.property ("zoom-focus"))) {
2309 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2312 if ((prop = node.property ("zoom"))) {
2313 reset_zoom (PBD::atof (prop->value()));
2315 reset_zoom (frames_per_unit);
2318 if ((prop = node.property ("snap-to"))) {
2319 set_snap_to ((SnapType) atoi (prop->value()));
2322 if ((prop = node.property ("snap-mode"))) {
2323 set_snap_mode ((SnapMode) atoi (prop->value()));
2326 if ((prop = node.property ("mouse-mode"))) {
2327 MouseMode m = str2mousemode(prop->value());
2328 set_mouse_mode (m, true);
2330 set_mouse_mode (MouseObject, true);
2333 if ((prop = node.property ("left-frame")) != 0){
2335 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2336 reset_x_origin (pos);
2340 if ((prop = node.property ("y-origin")) != 0) {
2341 reset_y_origin (atof (prop->value ()));
2344 if ((prop = node.property ("internal-edit"))) {
2345 bool yn = string_is_affirmative (prop->value());
2346 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2348 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2349 tact->set_active (!yn);
2350 tact->set_active (yn);
2354 if ((prop = node.property ("join-object-range"))) {
2355 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2358 if ((prop = node.property ("edit-point"))) {
2359 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2362 if ((prop = node.property ("show-measures"))) {
2363 bool yn = string_is_affirmative (prop->value());
2364 _show_measures = yn;
2365 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2367 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2368 /* do it twice to force the change */
2369 tact->set_active (!yn);
2370 tact->set_active (yn);
2374 if ((prop = node.property ("follow-playhead"))) {
2375 bool yn = string_is_affirmative (prop->value());
2376 set_follow_playhead (yn);
2377 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2379 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2380 if (tact->get_active() != yn) {
2381 tact->set_active (yn);
2386 if ((prop = node.property ("stationary-playhead"))) {
2387 bool yn = (prop->value() == "yes");
2388 set_stationary_playhead (yn);
2389 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2391 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2392 if (tact->get_active() != yn) {
2393 tact->set_active (yn);
2398 if ((prop = node.property ("region-list-sort-type"))) {
2399 RegionListSortType st;
2400 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2403 if ((prop = node.property ("xfades-visible"))) {
2404 bool yn = string_is_affirmative (prop->value());
2405 _xfade_visibility = !yn;
2406 // set_xfade_visibility (yn);
2409 if ((prop = node.property ("show-editor-mixer"))) {
2411 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2414 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2415 bool yn = string_is_affirmative (prop->value());
2417 /* do it twice to force the change */
2419 tact->set_active (!yn);
2420 tact->set_active (yn);
2423 if ((prop = node.property ("show-editor-list"))) {
2425 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2428 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2429 bool yn = string_is_affirmative (prop->value());
2431 /* do it twice to force the change */
2433 tact->set_active (!yn);
2434 tact->set_active (yn);
2437 if ((prop = node.property (X_("editor-list-page")))) {
2438 the_notebook.set_current_page (atoi (prop->value ()));
2441 if ((prop = node.property (X_("show-marker-lines")))) {
2442 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2444 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2445 bool yn = string_is_affirmative (prop->value ());
2447 tact->set_active (!yn);
2448 tact->set_active (yn);
2451 XMLNodeList children = node.children ();
2452 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2453 selection->set_state (**i, Stateful::current_state_version);
2454 _regions->set_state (**i);
2461 Editor::get_state ()
2463 XMLNode* node = new XMLNode ("Editor");
2466 _id.print (buf, sizeof (buf));
2467 node->add_property ("id", buf);
2469 if (is_realized()) {
2470 Glib::RefPtr<Gdk::Window> win = get_window();
2472 int x, y, xoff, yoff, width, height;
2473 win->get_root_origin(x, y);
2474 win->get_position(xoff, yoff);
2475 win->get_size(width, height);
2477 XMLNode* geometry = new XMLNode ("geometry");
2479 snprintf(buf, sizeof(buf), "%d", width);
2480 geometry->add_property("x-size", string(buf));
2481 snprintf(buf, sizeof(buf), "%d", height);
2482 geometry->add_property("y-size", string(buf));
2483 snprintf(buf, sizeof(buf), "%d", x);
2484 geometry->add_property("x-pos", string(buf));
2485 snprintf(buf, sizeof(buf), "%d", y);
2486 geometry->add_property("y-pos", string(buf));
2487 snprintf(buf, sizeof(buf), "%d", xoff);
2488 geometry->add_property("x-off", string(buf));
2489 snprintf(buf, sizeof(buf), "%d", yoff);
2490 geometry->add_property("y-off", string(buf));
2491 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2492 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2493 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2494 geometry->add_property("edit-vertical-pane-pos", string(buf));
2496 node->add_child_nocopy (*geometry);
2499 maybe_add_mixer_strip_width (*node);
2501 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2502 node->add_property ("zoom-focus", buf);
2503 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2504 node->add_property ("zoom", buf);
2505 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2506 node->add_property ("snap-to", buf);
2507 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2508 node->add_property ("snap-mode", buf);
2510 node->add_property ("edit-point", enum_2_string (_edit_point));
2512 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2513 node->add_property ("playhead", buf);
2514 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2515 node->add_property ("left-frame", buf);
2516 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2517 node->add_property ("y-origin", buf);
2519 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2520 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2521 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2522 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2523 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2524 node->add_property ("mouse-mode", enum2str(mouse_mode));
2525 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2526 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2528 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2530 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2531 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2534 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2536 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2537 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2540 snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
2541 node->add_property (X_("editor-list-page"), buf);
2543 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2545 node->add_child_nocopy (selection->get_state ());
2546 node->add_child_nocopy (_regions->get_state ());
2553 /** @param y y offset from the top of all trackviews.
2554 * @return pair: TimeAxisView that y is over, layer index.
2555 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2556 * in stacked region display mode, otherwise 0.
2558 std::pair<TimeAxisView *, layer_t>
2559 Editor::trackview_by_y_position (double y)
2561 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2563 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2569 return std::make_pair ( (TimeAxisView *) 0, 0);
2572 /** Snap a position to the grid, if appropriate, taking into account current
2573 * grid settings and also the state of any snap modifier keys that may be pressed.
2574 * @param start Position to snap.
2575 * @param event Event to get current key modifier information from, or 0.
2578 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2580 if (!_session || !event) {
2584 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2585 if (_snap_mode == SnapOff) {
2586 snap_to_internal (start, direction, for_mark);
2589 if (_snap_mode != SnapOff) {
2590 snap_to_internal (start, direction, for_mark);
2596 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2598 if (!_session || _snap_mode == SnapOff) {
2602 snap_to_internal (start, direction, for_mark);
2606 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2608 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2609 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2611 switch (_snap_type) {
2612 case SnapToTimecodeFrame:
2613 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2614 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2616 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2620 case SnapToTimecodeSeconds:
2621 if (_session->timecode_offset_negative())
2623 start += _session->timecode_offset ();
2625 start -= _session->timecode_offset ();
2627 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2628 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2630 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2633 if (_session->timecode_offset_negative())
2635 start -= _session->timecode_offset ();
2637 start += _session->timecode_offset ();
2641 case SnapToTimecodeMinutes:
2642 if (_session->timecode_offset_negative())
2644 start += _session->timecode_offset ();
2646 start -= _session->timecode_offset ();
2648 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2649 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2651 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2653 if (_session->timecode_offset_negative())
2655 start -= _session->timecode_offset ();
2657 start += _session->timecode_offset ();
2661 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2667 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2669 const framepos_t one_second = _session->frame_rate();
2670 const framepos_t one_minute = _session->frame_rate() * 60;
2671 framepos_t presnap = start;
2675 switch (_snap_type) {
2676 case SnapToTimecodeFrame:
2677 case SnapToTimecodeSeconds:
2678 case SnapToTimecodeMinutes:
2679 return timecode_snap_to_internal (start, direction, for_mark);
2682 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2683 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2685 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2690 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2691 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2693 start = (framepos_t) floor ((double) start / one_second) * one_second;
2698 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2699 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2701 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2706 start = _session->tempo_map().round_to_bar (start, direction);
2710 start = _session->tempo_map().round_to_beat (start, direction);
2713 case SnapToBeatDiv32:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2716 case SnapToBeatDiv28:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2719 case SnapToBeatDiv24:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2722 case SnapToBeatDiv20:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2725 case SnapToBeatDiv16:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2728 case SnapToBeatDiv14:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2731 case SnapToBeatDiv12:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2734 case SnapToBeatDiv10:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2737 case SnapToBeatDiv8:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2740 case SnapToBeatDiv7:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2743 case SnapToBeatDiv6:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2746 case SnapToBeatDiv5:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2749 case SnapToBeatDiv4:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2752 case SnapToBeatDiv3:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2755 case SnapToBeatDiv2:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2764 _session->locations()->marks_either_side (start, before, after);
2766 if (before == max_framepos) {
2768 } else if (after == max_framepos) {
2770 } else if (before != max_framepos && after != max_framepos) {
2771 /* have before and after */
2772 if ((start - before) < (after - start)) {
2781 case SnapToRegionStart:
2782 case SnapToRegionEnd:
2783 case SnapToRegionSync:
2784 case SnapToRegionBoundary:
2785 if (!region_boundary_cache.empty()) {
2787 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2788 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2790 if (direction > 0) {
2791 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2793 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2796 if (next != region_boundary_cache.begin ()) {
2801 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2802 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2804 if (start > (p + n) / 2) {
2813 switch (_snap_mode) {
2819 if (presnap > start) {
2820 if (presnap > (start + unit_to_frame(snap_threshold))) {
2824 } else if (presnap < start) {
2825 if (presnap < (start - unit_to_frame(snap_threshold))) {
2831 /* handled at entry */
2839 Editor::setup_toolbar ()
2843 /* Mode Buttons (tool selection) */
2845 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2846 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2847 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2848 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2849 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2850 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2851 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2852 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2854 HBox* mode_box = manage(new HBox);
2855 mode_box->set_border_width (2);
2856 mode_box->set_spacing(4);
2858 /* table containing mode buttons */
2860 HBox* mouse_mode_button_box = manage (new HBox ());
2862 if (Profile->get_sae()) {
2863 mouse_mode_button_box->pack_start (mouse_move_button);
2865 mouse_mode_button_box->pack_start (mouse_move_button);
2866 mouse_mode_button_box->pack_start (join_object_range_button);
2867 mouse_mode_button_box->pack_start (mouse_select_button);
2870 mouse_mode_button_box->pack_start (mouse_zoom_button);
2872 if (!Profile->get_sae()) {
2873 mouse_mode_button_box->pack_start (mouse_gain_button);
2876 mouse_mode_button_box->pack_start (mouse_timefx_button);
2877 mouse_mode_button_box->pack_start (mouse_audition_button);
2878 mouse_mode_button_box->pack_start (internal_edit_button);
2880 vector<string> edit_mode_strings;
2881 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2882 if (!Profile->get_sae()) {
2883 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2885 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2887 edit_mode_selector.set_name ("EditModeSelector");
2888 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2889 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2891 mode_box->pack_start (edit_mode_selector);
2892 mode_box->pack_start (*mouse_mode_button_box);
2894 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2895 _mouse_mode_tearoff->set_name ("MouseModeBase");
2896 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2898 if (Profile->get_sae()) {
2899 _mouse_mode_tearoff->set_can_be_torn_off (false);
2902 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2903 &_mouse_mode_tearoff->tearoff_window()));
2904 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2905 &_mouse_mode_tearoff->tearoff_window(), 1));
2906 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window()));
2908 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window(), 1));
2911 mouse_move_button.set_mode (false);
2912 mouse_select_button.set_mode (false);
2913 mouse_gain_button.set_mode (false);
2914 mouse_zoom_button.set_mode (false);
2915 mouse_timefx_button.set_mode (false);
2916 mouse_audition_button.set_mode (false);
2917 join_object_range_button.set_mode (false);
2919 mouse_move_button.set_name ("MouseModeButton");
2920 mouse_select_button.set_name ("MouseModeButton");
2921 mouse_gain_button.set_name ("MouseModeButton");
2922 mouse_zoom_button.set_name ("MouseModeButton");
2923 mouse_timefx_button.set_name ("MouseModeButton");
2924 mouse_audition_button.set_name ("MouseModeButton");
2925 internal_edit_button.set_name ("MouseModeButton");
2926 join_object_range_button.set_name ("MouseModeButton");
2928 mouse_move_button.unset_flags (CAN_FOCUS);
2929 mouse_select_button.unset_flags (CAN_FOCUS);
2930 mouse_gain_button.unset_flags (CAN_FOCUS);
2931 mouse_zoom_button.unset_flags (CAN_FOCUS);
2932 mouse_timefx_button.unset_flags (CAN_FOCUS);
2933 mouse_audition_button.unset_flags (CAN_FOCUS);
2934 internal_edit_button.unset_flags (CAN_FOCUS);
2935 join_object_range_button.unset_flags (CAN_FOCUS);
2939 _zoom_box.set_spacing (1);
2940 _zoom_box.set_border_width (0);
2942 zoom_in_button.set_name ("EditorTimeButton");
2943 zoom_in_button.set_image (*(manage (new Image (Stock::ZOOM_IN, Gtk::ICON_SIZE_MENU))));
2944 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2946 zoom_out_button.set_name ("EditorTimeButton");
2947 zoom_out_button.set_image (*(manage (new Image (Stock::ZOOM_OUT, Gtk::ICON_SIZE_MENU))));
2948 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2950 zoom_out_full_button.set_name ("EditorTimeButton");
2951 zoom_out_full_button.set_image (*(manage (new Image (Stock::ZOOM_100, Gtk::ICON_SIZE_MENU))));
2952 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2954 zoom_focus_selector.set_name ("ZoomFocusSelector");
2955 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2956 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2958 _zoom_box.pack_start (zoom_out_button, false, false);
2959 _zoom_box.pack_start (zoom_in_button, false, false);
2960 _zoom_box.pack_start (zoom_out_full_button, false, false);
2962 _zoom_box.pack_start (zoom_focus_selector);
2964 /* Track zoom buttons */
2965 tav_expand_button.set_name ("TrackHeightButton");
2966 tav_expand_button.set_size_request(-1,20);
2967 tav_expand_button.add (*(manage (new Image (::get_icon("tav_exp")))));
2968 tav_expand_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), true));
2970 tav_shrink_button.set_name ("TrackHeightButton");
2971 tav_shrink_button.set_size_request(-1,20);
2972 tav_shrink_button.add (*(manage (new Image (::get_icon("tav_shrink")))));
2973 tav_shrink_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::tav_zoom_step), false));
2975 _zoom_box.pack_start (tav_shrink_button);
2976 _zoom_box.pack_start (tav_expand_button);
2978 _zoom_tearoff = manage (new TearOff (_zoom_box));
2980 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981 &_zoom_tearoff->tearoff_window()));
2982 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983 &_zoom_tearoff->tearoff_window(), 0));
2984 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_zoom_tearoff->tearoff_window()));
2986 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_zoom_tearoff->tearoff_window(), 0));
2989 snap_box.set_spacing (1);
2990 snap_box.set_border_width (2);
2992 snap_type_selector.set_name ("SnapTypeSelector");
2993 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2994 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2996 snap_mode_selector.set_name ("SnapModeSelector");
2997 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2998 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3000 edit_point_selector.set_name ("EditPointSelector");
3001 set_popdown_strings (edit_point_selector, edit_point_strings, true);
3002 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3004 snap_box.pack_start (snap_mode_selector, false, false);
3005 snap_box.pack_start (snap_type_selector, false, false);
3006 snap_box.pack_start (edit_point_selector, false, false);
3010 HBox *nudge_box = manage (new HBox);
3011 nudge_box->set_spacing(1);
3012 nudge_box->set_border_width (2);
3014 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3015 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3017 nudge_box->pack_start (nudge_backward_button, false, false);
3018 nudge_box->pack_start (nudge_forward_button, false, false);
3019 nudge_box->pack_start (nudge_clock, false, false);
3022 /* Pack everything in... */
3024 HBox* hbox = manage (new HBox);
3025 hbox->set_spacing(10);
3027 _tools_tearoff = manage (new TearOff (*hbox));
3028 _tools_tearoff->set_name ("MouseModeBase");
3029 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3031 if (Profile->get_sae()) {
3032 _tools_tearoff->set_can_be_torn_off (false);
3035 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window()));
3037 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window(), 0));
3039 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window()));
3041 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window(), 0));
3044 toolbar_hbox.set_spacing (10);
3045 toolbar_hbox.set_border_width (1);
3047 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3048 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3049 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3051 hbox->pack_start (snap_box, false, false);
3052 hbox->pack_start (*nudge_box, false, false);
3053 hbox->pack_start (panic_box, false, false);
3057 toolbar_base.set_name ("ToolBarBase");
3058 toolbar_base.add (toolbar_hbox);
3060 toolbar_frame.set_shadow_type (SHADOW_OUT);
3061 toolbar_frame.set_name ("BaseFrame");
3062 toolbar_frame.add (toolbar_base);
3066 Editor::setup_tooltips ()
3068 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3069 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3070 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3071 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3072 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3073 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
3074 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3075 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3076 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
3077 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
3078 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3079 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3080 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3081 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3082 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3083 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3084 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3085 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3086 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3087 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
3088 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
3089 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3093 Editor::midi_panic ()
3095 cerr << "MIDI panic\n";
3098 _session->midi_panic();
3103 Editor::setup_midi_toolbar ()
3107 /* Midi sound notes */
3108 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3109 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3110 midi_sound_notes.unset_flags (CAN_FOCUS);
3114 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3115 midi_panic_button.set_name("MidiPanicButton");
3116 act->connect_proxy (midi_panic_button);
3118 panic_box.pack_start (midi_sound_notes , true, true);
3119 panic_box.pack_start (midi_panic_button, true, true);
3123 Editor::convert_drop_to_paths (
3124 vector<string>& paths,
3125 const RefPtr<Gdk::DragContext>& /*context*/,
3128 const SelectionData& data,
3132 if (_session == 0) {
3136 vector<string> uris = data.get_uris();
3140 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3141 are actually URI lists. So do it by hand.
3144 if (data.get_target() != "text/plain") {
3148 /* Parse the "uri-list" format that Nautilus provides,
3149 where each pathname is delimited by \r\n.
3151 THERE MAY BE NO NULL TERMINATING CHAR!!!
3154 string txt = data.get_text();
3158 p = (const char *) malloc (txt.length() + 1);
3159 txt.copy ((char *) p, txt.length(), 0);
3160 ((char*)p)[txt.length()] = '\0';
3166 while (g_ascii_isspace (*p))
3170 while (*q && (*q != '\n') && (*q != '\r')) {
3177 while (q > p && g_ascii_isspace (*q))
3182 uris.push_back (string (p, q - p + 1));
3186 p = strchr (p, '\n');
3198 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3200 if ((*i).substr (0,7) == "file://") {
3203 PBD::url_decode (p);
3205 // scan forward past three slashes
3207 string::size_type slashcnt = 0;
3208 string::size_type n = 0;
3209 string::iterator x = p.begin();
3211 while (slashcnt < 3 && x != p.end()) {
3214 } else if (slashcnt == 3) {
3221 if (slashcnt != 3 || x == p.end()) {
3222 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3226 paths.push_back (p.substr (n - 1));
3234 Editor::new_tempo_section ()
3240 Editor::map_transport_state ()
3242 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3244 if (_session && _session->transport_stopped()) {
3245 have_pending_keyboard_selection = false;
3248 update_loop_range_view (true);
3253 Editor::State::State (PublicEditor const * e)
3255 selection = new Selection (e);
3258 Editor::State::~State ()
3264 Editor::begin_reversible_command (string name)
3267 _session->begin_reversible_command (name);
3272 Editor::commit_reversible_command ()
3275 _session->commit_reversible_command ();
3280 Editor::set_route_group_solo (Route& route, bool yn)
3282 RouteGroup *route_group;
3284 if ((route_group = route.route_group()) != 0) {
3285 route_group->apply (&Route::set_solo, yn, this);
3287 route.set_solo (yn, this);
3292 Editor::set_route_group_mute (Route& route, bool yn)
3294 RouteGroup *route_group = 0;
3296 if ((route_group = route.route_group()) != 0) {
3297 route_group->apply (&Route::set_mute, yn, this);
3299 route.set_mute (yn, this);
3304 Editor::history_changed ()
3308 if (undo_action && _session) {
3309 if (_session->undo_depth() == 0) {
3312 label = string_compose(_("Undo (%1)"), _session->next_undo());
3314 undo_action->property_label() = label;
3317 if (redo_action && _session) {
3318 if (_session->redo_depth() == 0) {
3321 label = string_compose(_("Redo (%1)"), _session->next_redo());
3323 redo_action->property_label() = label;
3328 Editor::duplicate_dialog (bool with_dialog)
3332 if (mouse_mode == MouseRange) {
3333 if (selection->time.length() == 0) {
3338 RegionSelection rs = get_regions_from_selection_and_entered ();
3340 if (mouse_mode != MouseRange && rs.empty()) {
3346 ArdourDialog win (_("Duplicate"));
3347 Label label (_("Number of duplications:"));
3348 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3349 SpinButton spinner (adjustment, 0.0, 1);
3352 win.get_vbox()->set_spacing (12);
3353 win.get_vbox()->pack_start (hbox);
3354 hbox.set_border_width (6);
3355 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3357 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3358 place, visually. so do this by hand.
3361 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3362 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3363 spinner.grab_focus();
3369 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3370 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3371 win.set_default_response (RESPONSE_ACCEPT);
3373 win.set_position (WIN_POS_MOUSE);
3375 spinner.grab_focus ();
3377 switch (win.run ()) {
3378 case RESPONSE_ACCEPT:
3384 times = adjustment.get_value();
3387 if (mouse_mode == MouseRange) {
3388 duplicate_selection (times);
3390 duplicate_some_regions (rs, times);
3395 Editor::show_verbose_canvas_cursor ()
3397 verbose_canvas_cursor->raise_to_top();
3398 verbose_canvas_cursor->show();
3399 verbose_cursor_visible = true;
3403 Editor::hide_verbose_canvas_cursor ()
3405 verbose_canvas_cursor->hide();
3406 verbose_cursor_visible = false;
3410 Editor::clamp_verbose_cursor_x (double x)
3415 x = min (_canvas_width - 200.0, x);
3421 Editor::clamp_verbose_cursor_y (double y)
3423 if (y < canvas_timebars_vsize) {
3424 y = canvas_timebars_vsize;
3426 y = min (_canvas_height - 50, y);
3432 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3434 verbose_canvas_cursor->property_text() = txt.c_str();
3439 track_canvas->get_pointer (x, y);
3440 track_canvas->window_to_world (x, y, wx, wy);
3445 /* don't get too close to the edge */
3446 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3447 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3449 show_verbose_canvas_cursor ();
3453 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3455 verbose_canvas_cursor->property_text() = txt.c_str();
3456 /* don't get too close to the edge */
3457 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3458 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3462 Editor::set_verbose_canvas_cursor_text (const string & txt)
3464 verbose_canvas_cursor->property_text() = txt.c_str();
3468 Editor::set_edit_mode (EditMode m)
3470 Config->set_edit_mode (m);
3474 Editor::cycle_edit_mode ()
3476 switch (Config->get_edit_mode()) {
3478 if (Profile->get_sae()) {
3479 Config->set_edit_mode (Lock);
3481 Config->set_edit_mode (Splice);
3485 Config->set_edit_mode (Lock);
3488 Config->set_edit_mode (Slide);
3494 Editor::edit_mode_selection_done ()
3496 Config->set_edit_mode (string_to_edit_mode (edit_mode_selector.get_active_text ()));
3500 Editor::snap_type_selection_done ()
3502 string choice = snap_type_selector.get_active_text();
3503 SnapType snaptype = SnapToBeat;
3505 if (choice == _("Beats/2")) {
3506 snaptype = SnapToBeatDiv2;
3507 } else if (choice == _("Beats/3")) {
3508 snaptype = SnapToBeatDiv3;
3509 } else if (choice == _("Beats/4")) {
3510 snaptype = SnapToBeatDiv4;
3511 } else if (choice == _("Beats/5")) {
3512 snaptype = SnapToBeatDiv5;
3513 } else if (choice == _("Beats/6")) {
3514 snaptype = SnapToBeatDiv6;
3515 } else if (choice == _("Beats/7")) {
3516 snaptype = SnapToBeatDiv7;
3517 } else if (choice == _("Beats/8")) {
3518 snaptype = SnapToBeatDiv8;
3519 } else if (choice == _("Beats/10")) {
3520 snaptype = SnapToBeatDiv10;
3521 } else if (choice == _("Beats/12")) {
3522 snaptype = SnapToBeatDiv12;
3523 } else if (choice == _("Beats/14")) {
3524 snaptype = SnapToBeatDiv14;
3525 } else if (choice == _("Beats/16")) {
3526 snaptype = SnapToBeatDiv16;
3527 } else if (choice == _("Beats/20")) {
3528 snaptype = SnapToBeatDiv20;
3529 } else if (choice == _("Beats/24")) {
3530 snaptype = SnapToBeatDiv24;
3531 } else if (choice == _("Beats/28")) {
3532 snaptype = SnapToBeatDiv28;
3533 } else if (choice == _("Beats/32")) {
3534 snaptype = SnapToBeatDiv32;
3535 } else if (choice == _("Beats")) {
3536 snaptype = SnapToBeat;
3537 } else if (choice == _("Bars")) {
3538 snaptype = SnapToBar;
3539 } else if (choice == _("Marks")) {
3540 snaptype = SnapToMark;
3541 } else if (choice == _("Region starts")) {
3542 snaptype = SnapToRegionStart;
3543 } else if (choice == _("Region ends")) {
3544 snaptype = SnapToRegionEnd;
3545 } else if (choice == _("Region bounds")) {
3546 snaptype = SnapToRegionBoundary;
3547 } else if (choice == _("Region syncs")) {
3548 snaptype = SnapToRegionSync;
3549 } else if (choice == _("CD Frames")) {
3550 snaptype = SnapToCDFrame;
3551 } else if (choice == _("Timecode Frames")) {
3552 snaptype = SnapToTimecodeFrame;
3553 } else if (choice == _("Timecode Seconds")) {
3554 snaptype = SnapToTimecodeSeconds;
3555 } else if (choice == _("Timecode Minutes")) {
3556 snaptype = SnapToTimecodeMinutes;
3557 } else if (choice == _("Seconds")) {
3558 snaptype = SnapToSeconds;
3559 } else if (choice == _("Minutes")) {
3560 snaptype = SnapToMinutes;
3563 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3565 ract->set_active ();
3570 Editor::snap_mode_selection_done ()
3572 string choice = snap_mode_selector.get_active_text();
3573 SnapMode mode = SnapNormal;
3575 if (choice == _("No Grid")) {
3577 } else if (choice == _("Grid")) {
3579 } else if (choice == _("Magnetic")) {
3580 mode = SnapMagnetic;
3583 RefPtr<RadioAction> ract = snap_mode_action (mode);
3586 ract->set_active (true);
3591 Editor::cycle_edit_point (bool with_marker)
3593 switch (_edit_point) {
3595 set_edit_point_preference (EditAtPlayhead);
3597 case EditAtPlayhead:
3599 set_edit_point_preference (EditAtSelectedMarker);
3601 set_edit_point_preference (EditAtMouse);
3604 case EditAtSelectedMarker:
3605 set_edit_point_preference (EditAtMouse);
3611 Editor::edit_point_selection_done ()
3613 string choice = edit_point_selector.get_active_text();
3614 EditPoint ep = EditAtSelectedMarker;
3616 if (choice == _("Marker")) {
3617 set_edit_point_preference (EditAtSelectedMarker);
3618 } else if (choice == _("Playhead")) {
3619 set_edit_point_preference (EditAtPlayhead);
3621 set_edit_point_preference (EditAtMouse);
3624 RefPtr<RadioAction> ract = edit_point_action (ep);
3627 ract->set_active (true);
3632 Editor::zoom_focus_selection_done ()
3634 string choice = zoom_focus_selector.get_active_text();
3635 ZoomFocus focus_type = ZoomFocusLeft;
3637 if (choice == _("Left")) {
3638 focus_type = ZoomFocusLeft;
3639 } else if (choice == _("Right")) {
3640 focus_type = ZoomFocusRight;
3641 } else if (choice == _("Center")) {
3642 focus_type = ZoomFocusCenter;
3643 } else if (choice == _("Playhead")) {
3644 focus_type = ZoomFocusPlayhead;
3645 } else if (choice == _("Mouse")) {
3646 focus_type = ZoomFocusMouse;
3647 } else if (choice == _("Edit point")) {
3648 focus_type = ZoomFocusEdit;
3651 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3654 ract->set_active ();
3659 Editor::edit_controls_button_release (GdkEventButton* ev)
3661 if (Keyboard::is_context_menu_event (ev)) {
3662 ARDOUR_UI::instance()->add_route (this);
3668 Editor::mouse_select_button_release (GdkEventButton* ev)
3670 /* this handles just right-clicks */
3672 if (ev->button != 3) {
3680 Editor::set_zoom_focus (ZoomFocus f)
3682 string str = zoom_focus_strings[(int)f];
3684 if (str != zoom_focus_selector.get_active_text()) {
3685 zoom_focus_selector.set_active_text (str);
3688 if (zoom_focus != f) {
3691 ZoomFocusChanged (); /* EMIT_SIGNAL */
3698 Editor::ensure_float (Window& win)
3700 win.set_transient_for (*this);
3704 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3706 /* recover or initialize pane positions. do this here rather than earlier because
3707 we don't want the positions to change the child allocations, which they seem to do.
3713 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3725 width = default_width;
3726 height = default_height;
3728 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3730 prop = geometry->property ("x-size");
3732 width = atoi (prop->value());
3734 prop = geometry->property ("y-size");
3736 height = atoi (prop->value());
3740 if (which == static_cast<Paned*> (&edit_pane)) {
3742 if (done & Horizontal) {
3746 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3747 /* initial allocation is 90% to canvas, 10% to notebook */
3748 pos = (int) floor (alloc.get_width() * 0.90f);
3749 snprintf (buf, sizeof(buf), "%d", pos);
3751 pos = atoi (prop->value());
3754 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3755 edit_pane.set_position (pos);
3756 pre_maximal_horizontal_pane_position = pos;
3759 done = (Pane) (done | Horizontal);
3761 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3763 if (done & Vertical) {
3767 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3768 /* initial allocation is 90% to canvas, 10% to summary */
3769 pos = (int) floor (alloc.get_height() * 0.90f);
3770 snprintf (buf, sizeof(buf), "%d", pos);
3772 pos = atoi (prop->value());
3775 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3776 editor_summary_pane.set_position (pos);
3777 pre_maximal_vertical_pane_position = pos;
3780 done = (Pane) (done | Vertical);
3785 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3787 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3788 top_hbox.remove (toolbar_frame);
3793 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3795 if (toolbar_frame.get_parent() == 0) {
3796 top_hbox.pack_end (toolbar_frame);
3801 Editor::set_show_measures (bool yn)
3803 if (_show_measures != yn) {
3806 if ((_show_measures = yn) == true) {
3808 tempo_lines->show();
3816 Editor::toggle_follow_playhead ()
3818 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3820 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3821 set_follow_playhead (tact->get_active());
3826 Editor::set_follow_playhead (bool yn)
3828 if (_follow_playhead != yn) {
3829 if ((_follow_playhead = yn) == true) {
3831 reset_x_origin_to_follow_playhead ();
3838 Editor::toggle_stationary_playhead ()
3840 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3842 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3843 set_stationary_playhead (tact->get_active());
3848 Editor::set_stationary_playhead (bool yn)
3850 if (_stationary_playhead != yn) {
3851 if ((_stationary_playhead = yn) == true) {
3853 // FIXME need a 3.0 equivalent of this 2.X call
3854 // update_current_screen ();
3861 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3863 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3865 xfade->set_active (!xfade->active());
3870 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3872 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3874 xfade->set_follow_overlap (!xfade->following_overlap());
3879 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3881 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3887 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3891 switch (cew.run ()) {
3892 case RESPONSE_ACCEPT:
3899 PropertyChange all_crossfade_properties;
3900 all_crossfade_properties.add (ARDOUR::Properties::active);
3901 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3902 xfade->PropertyChanged (all_crossfade_properties);
3906 Editor::playlist_selector () const
3908 return *_playlist_selector;
3912 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3916 switch (_snap_type) {
3921 case SnapToBeatDiv32:
3924 case SnapToBeatDiv28:
3927 case SnapToBeatDiv24:
3930 case SnapToBeatDiv20:
3933 case SnapToBeatDiv16:
3936 case SnapToBeatDiv14:
3939 case SnapToBeatDiv12:
3942 case SnapToBeatDiv10:
3945 case SnapToBeatDiv8:
3948 case SnapToBeatDiv7:
3951 case SnapToBeatDiv6:
3954 case SnapToBeatDiv5:
3957 case SnapToBeatDiv4:
3960 case SnapToBeatDiv3:
3963 case SnapToBeatDiv2:
3969 return _session->tempo_map().meter_at (position).beats_per_bar();
3974 case SnapToTimecodeFrame:
3975 case SnapToTimecodeSeconds:
3976 case SnapToTimecodeMinutes:
3979 case SnapToRegionStart:
3980 case SnapToRegionEnd:
3981 case SnapToRegionSync:
3982 case SnapToRegionBoundary:
3992 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3996 ret = nudge_clock.current_duration (pos);
3997 next = ret + 1; /* XXXX fix me */
4003 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4005 ArdourDialog dialog (_("Playlist Deletion"));
4006 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4007 "If left alone, no audio files used by it will be cleaned.\n"
4008 "If deleted, audio files used by it alone by will cleaned."),
4011 dialog.set_position (WIN_POS_CENTER);
4012 dialog.get_vbox()->pack_start (label);
4016 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
4017 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
4018 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4020 switch (dialog.run ()) {
4021 case RESPONSE_ACCEPT:
4022 /* delete the playlist */
4026 case RESPONSE_REJECT:
4027 /* keep the playlist */
4039 Editor::audio_region_selection_covers (framepos_t where)
4041 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4042 if ((*a)->region()->covers (where)) {
4051 Editor::prepare_for_cleanup ()
4053 cut_buffer->clear_regions ();
4054 cut_buffer->clear_playlists ();
4056 selection->clear_regions ();
4057 selection->clear_playlists ();
4059 _regions->suspend_redisplay ();
4063 Editor::finish_cleanup ()
4065 _regions->resume_redisplay ();
4069 Editor::transport_loop_location()
4072 return _session->locations()->auto_loop_location();
4079 Editor::transport_punch_location()
4082 return _session->locations()->auto_punch_location();
4089 Editor::control_layout_scroll (GdkEventScroll* ev)
4091 if (Keyboard::some_magic_widget_has_focus()) {
4095 switch (ev->direction) {
4097 scroll_tracks_up_line ();
4101 case GDK_SCROLL_DOWN:
4102 scroll_tracks_down_line ();
4106 /* no left/right handling yet */
4114 Editor::session_state_saved (string)
4117 _snapshots->redisplay ();
4121 Editor::maximise_editing_space ()
4123 _mouse_mode_tearoff->set_visible (false);
4124 _tools_tearoff->set_visible (false);
4125 _zoom_tearoff->set_visible (false);
4127 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4128 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4129 pre_maximal_editor_width = this->get_width ();
4130 pre_maximal_editor_height = this->get_height ();
4132 if (post_maximal_horizontal_pane_position == 0) {
4133 post_maximal_horizontal_pane_position = edit_pane.get_width();
4136 if (post_maximal_vertical_pane_position == 0) {
4137 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4142 if (post_maximal_editor_width) {
4143 edit_pane.set_position (post_maximal_horizontal_pane_position -
4144 abs(post_maximal_editor_width - pre_maximal_editor_width));
4146 edit_pane.set_position (post_maximal_horizontal_pane_position);
4149 if (post_maximal_editor_height) {
4150 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4151 abs(post_maximal_editor_height - pre_maximal_editor_height));
4153 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4156 if (Config->get_keep_tearoffs()) {
4157 _mouse_mode_tearoff->set_visible (true);
4158 _tools_tearoff->set_visible (true);
4159 _zoom_tearoff->set_visible (true);
4165 Editor::restore_editing_space ()
4167 // user changed width/height of panes during fullscreen
4169 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4170 post_maximal_horizontal_pane_position = edit_pane.get_position();
4173 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4174 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4179 _mouse_mode_tearoff->set_visible (true);
4180 _tools_tearoff->set_visible (true);
4181 _zoom_tearoff->set_visible (true);
4182 post_maximal_editor_width = this->get_width();
4183 post_maximal_editor_height = this->get_height();
4185 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4186 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4190 * Make new playlists for a given track and also any others that belong
4191 * to the same active route group with the `edit' property.
4196 Editor::new_playlists (TimeAxisView* v)
4198 begin_reversible_command (_("new playlists"));
4199 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4200 _session->playlists->get (playlists);
4201 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4202 commit_reversible_command ();
4206 * Use a copy of the current playlist for a given track and also any others that belong
4207 * to the same active route group with the `edit' property.
4212 Editor::copy_playlists (TimeAxisView* v)
4214 begin_reversible_command (_("copy playlists"));
4215 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4216 _session->playlists->get (playlists);
4217 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4218 commit_reversible_command ();
4221 /** Clear the current playlist for a given track and also any others that belong
4222 * to the same active route group with the `edit' property.
4227 Editor::clear_playlists (TimeAxisView* v)
4229 begin_reversible_command (_("clear playlists"));
4230 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4231 _session->playlists->get (playlists);
4232 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4233 commit_reversible_command ();
4237 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4239 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4243 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4245 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4249 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4251 atv.clear_playlist ();
4255 Editor::on_key_press_event (GdkEventKey* ev)
4257 return key_press_focus_accelerator_handler (*this, ev);
4261 Editor::on_key_release_event (GdkEventKey* ev)
4263 return Gtk::Window::on_key_release_event (ev);
4264 // return key_press_focus_accelerator_handler (*this, ev);
4267 /** Queue up a change to the viewport x origin.
4268 * @param frame New x origin.
4271 Editor::reset_x_origin (framepos_t frame)
4273 queue_visual_change (frame);
4277 Editor::reset_y_origin (double y)
4279 queue_visual_change_y (y);
4283 Editor::reset_zoom (double fpu)
4285 queue_visual_change (fpu);
4289 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4291 reset_x_origin (frame);
4294 if (!no_save_visual) {
4295 undo_visual_stack.push_back (current_visual_state(false));
4299 Editor::VisualState*
4300 Editor::current_visual_state (bool with_tracks)
4302 VisualState* vs = new VisualState;
4303 vs->y_position = vertical_adjustment.get_value();
4304 vs->frames_per_unit = frames_per_unit;
4305 vs->leftmost_frame = leftmost_frame;
4306 vs->zoom_focus = zoom_focus;
4309 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4310 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4318 Editor::undo_visual_state ()
4320 if (undo_visual_stack.empty()) {
4324 redo_visual_stack.push_back (current_visual_state());
4326 VisualState* vs = undo_visual_stack.back();
4327 undo_visual_stack.pop_back();
4328 use_visual_state (*vs);
4332 Editor::redo_visual_state ()
4334 if (redo_visual_stack.empty()) {
4338 undo_visual_stack.push_back (current_visual_state());
4340 VisualState* vs = redo_visual_stack.back();
4341 redo_visual_stack.pop_back();
4342 use_visual_state (*vs);
4346 Editor::swap_visual_state ()
4348 if (undo_visual_stack.empty()) {
4349 redo_visual_state ();
4351 undo_visual_state ();
4356 Editor::use_visual_state (VisualState& vs)
4358 no_save_visual = true;
4360 _routes->suspend_redisplay ();
4362 vertical_adjustment.set_value (vs.y_position);
4364 set_zoom_focus (vs.zoom_focus);
4365 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4367 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4368 TrackViewList::iterator t;
4370 /* check if the track still exists - it could have been deleted */
4372 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4373 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4378 if (!vs.track_states.empty()) {
4379 _routes->update_visibility ();
4382 _routes->resume_redisplay ();
4384 no_save_visual = false;
4388 Editor::set_frames_per_unit (double fpu)
4390 /* this is the core function that controls the zoom level of the canvas. it is called
4391 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4394 if (fpu == frames_per_unit) {
4403 /* don't allow zooms that fit more than the maximum number
4404 of frames into an 800 pixel wide space.
4407 if (max_framepos / fpu < 800.0) {
4412 tempo_lines->tempo_map_changed();
4414 frames_per_unit = fpu;
4419 Editor::post_zoom ()
4421 // convert fpu to frame count
4423 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4425 if (frames_per_unit != zoom_range_clock.current_duration()) {
4426 zoom_range_clock.set (frames);
4429 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4430 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4431 (*i)->reshow_selection (selection->time);
4435 ZoomChanged (); /* EMIT_SIGNAL */
4437 //reset_scrolling_region ();
4439 if (playhead_cursor) {
4440 playhead_cursor->set_position (playhead_cursor->current_frame);
4443 refresh_location_display();
4444 _summary->set_overlays_dirty ();
4446 update_marker_labels ();
4452 Editor::queue_visual_change (framepos_t where)
4454 pending_visual_change.add (VisualChange::TimeOrigin);
4455 pending_visual_change.time_origin = where;
4456 ensure_visual_change_idle_handler ();
4460 Editor::queue_visual_change (double fpu)
4462 pending_visual_change.add (VisualChange::ZoomLevel);
4463 pending_visual_change.frames_per_unit = fpu;
4465 ensure_visual_change_idle_handler ();
4469 Editor::queue_visual_change_y (double y)
4471 pending_visual_change.add (VisualChange::YOrigin);
4472 pending_visual_change.y_origin = y;
4474 ensure_visual_change_idle_handler ();
4478 Editor::ensure_visual_change_idle_handler ()
4480 if (pending_visual_change.idle_handler_id < 0) {
4481 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4486 Editor::_idle_visual_changer (void* arg)
4488 return static_cast<Editor*>(arg)->idle_visual_changer ();
4492 Editor::idle_visual_changer ()
4494 VisualChange::Type p = pending_visual_change.pending;
4495 pending_visual_change.pending = (VisualChange::Type) 0;
4497 double const last_time_origin = horizontal_position ();
4499 if (p & VisualChange::TimeOrigin) {
4500 /* This is a bit of a hack, but set_frames_per_unit
4501 below will (if called) end up with the
4502 CrossfadeViews looking at Editor::leftmost_frame,
4503 and if we're changing origin and zoom in the same
4504 operation it will be the wrong value unless we
4508 leftmost_frame = pending_visual_change.time_origin;
4511 if (p & VisualChange::ZoomLevel) {
4512 set_frames_per_unit (pending_visual_change.frames_per_unit);
4514 compute_fixed_ruler_scale ();
4515 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4516 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4517 update_tempo_based_rulers ();
4519 if (p & VisualChange::TimeOrigin) {
4520 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4522 if (p & VisualChange::YOrigin) {
4523 vertical_adjustment.set_value (pending_visual_change.y_origin);
4526 if (last_time_origin == horizontal_position ()) {
4527 /* changed signal not emitted */
4528 update_fixed_rulers ();
4529 redisplay_tempo (true);
4532 _summary->set_overlays_dirty ();
4534 pending_visual_change.idle_handler_id = -1;
4535 return 0; /* this is always a one-shot call */
4538 struct EditorOrderTimeAxisSorter {
4539 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4540 return a->order () < b->order ();
4545 Editor::sort_track_selection (TrackViewList* sel)
4547 EditorOrderTimeAxisSorter cmp;
4552 selection->tracks.sort (cmp);
4557 Editor::get_preferred_edit_position (bool ignore_playhead)
4560 framepos_t where = 0;
4561 EditPoint ep = _edit_point;
4563 if (entered_marker) {
4564 return entered_marker->position();
4567 if (ignore_playhead && ep == EditAtPlayhead) {
4568 ep = EditAtSelectedMarker;
4572 case EditAtPlayhead:
4573 where = _session->audible_frame();
4576 case EditAtSelectedMarker:
4577 if (!selection->markers.empty()) {
4579 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4582 where = loc->start();
4593 if (!mouse_frame (where, ignored)) {
4594 /* XXX not right but what can we do ? */
4605 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4607 if (!_session) return;
4609 begin_reversible_command (cmd);
4613 if ((tll = transport_loop_location()) == 0) {
4614 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4615 XMLNode &before = _session->locations()->get_state();
4616 _session->locations()->add (loc, true);
4617 _session->set_auto_loop_location (loc);
4618 XMLNode &after = _session->locations()->get_state();
4619 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4621 XMLNode &before = tll->get_state();
4622 tll->set_hidden (false, this);
4623 tll->set (start, end);
4624 XMLNode &after = tll->get_state();
4625 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4628 commit_reversible_command ();
4632 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4634 if (!_session) return;
4636 begin_reversible_command (cmd);
4640 if ((tpl = transport_punch_location()) == 0) {
4641 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4642 XMLNode &before = _session->locations()->get_state();
4643 _session->locations()->add (loc, true);
4644 _session->set_auto_loop_location (loc);
4645 XMLNode &after = _session->locations()->get_state();
4646 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4649 XMLNode &before = tpl->get_state();
4650 tpl->set_hidden (false, this);
4651 tpl->set (start, end);
4652 XMLNode &after = tpl->get_state();
4653 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4656 commit_reversible_command ();
4659 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4660 * @param rs List to which found regions are added.
4661 * @param where Time to look at.
4662 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4665 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4667 const TrackViewList* tracks;
4670 tracks = &track_views;
4675 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4676 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4678 boost::shared_ptr<Track> tr;
4679 boost::shared_ptr<Playlist> pl;
4681 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4683 Playlist::RegionList* regions = pl->regions_at (
4684 (framepos_t) floor ( (double)where * tr->speed()));
4686 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4687 RegionView* rv = rtv->view()->find_view (*i);
4700 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4702 const TrackViewList* tracks;
4705 tracks = &track_views;
4710 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4711 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4713 boost::shared_ptr<Track> tr;
4714 boost::shared_ptr<Playlist> pl;
4716 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4718 Playlist::RegionList* regions = pl->regions_touched (
4719 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4721 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4723 RegionView* rv = rtv->view()->find_view (*i);
4736 /** Get regions using the following conditions:
4737 * 1. If the edit point is `mouse':
4738 * if the mouse is over a selected region, or no region, return all selected regions.
4739 * if the mouse is over an unselected region, return just that region.
4740 * 2. For all other edit points:
4741 * return the selected regions AND those that are both under the edit position
4742 * AND on a selected track, or on a track which is in the same active edit-enabled route group
4743 * as a selected region.
4745 * The rationale here is that the mouse edit point is special in that its position describes
4746 * both a time and a track; the other edit modes only describe a time.
4748 * @param rs Returned region list.
4752 Editor::get_regions_from_selection_and_edit_point ()
4754 if (_edit_point == EditAtMouse) {
4755 if (entered_regionview == 0 || selection->regions.contains (entered_regionview)) {
4756 return selection->regions;
4759 rs.add (entered_regionview);
4764 /* We're using the edit point, but its not EditAtMouse */
4766 /* Start with selected regions */
4767 RegionSelection rs = selection->regions;
4769 TrackViewList tracks = selection->tracks;
4771 /* Tracks is currently the set of selected tracks; add any other tracks that
4772 have regions that are in the same edit-activated route group as one of
4775 for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4777 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4778 if (g && g->is_active() && g->is_edit()) {
4779 tracks.add (axis_views_from_routes (g->route_list()));
4784 if (!tracks.empty()) {
4785 /* now find regions that are at the edit position on those tracks */
4786 framepos_t const where = get_preferred_edit_position ();
4787 get_regions_at (rs, where, tracks);
4795 Editor::get_regions_from_selection_and_entered ()
4797 RegionSelection rs = selection->regions;
4799 if (rs.empty() && entered_regionview) {
4800 rs.add (entered_regionview);
4807 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4809 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4811 RouteTimeAxisView* tatv;
4813 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4815 boost::shared_ptr<Playlist> pl;
4816 vector<boost::shared_ptr<Region> > results;
4818 boost::shared_ptr<Track> tr;
4820 if ((tr = tatv->track()) == 0) {
4825 if ((pl = (tr->playlist())) != 0) {
4826 pl->get_region_list_equivalent_regions (region, results);
4829 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4830 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4831 regions.push_back (marv);
4840 Editor::show_rhythm_ferret ()
4842 if (rhythm_ferret == 0) {
4843 rhythm_ferret = new RhythmFerret(*this);
4846 rhythm_ferret->set_session (_session);
4847 rhythm_ferret->show ();
4848 rhythm_ferret->present ();
4852 Editor::first_idle ()
4854 MessageDialog* dialog = 0;
4856 if (track_views.size() > 1) {
4857 dialog = new MessageDialog (*this,
4858 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4863 ARDOUR_UI::instance()->flush_pending ();
4866 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4870 // first idle adds route children (automation tracks), so we need to redisplay here
4871 _routes->redisplay ();
4879 Editor::_idle_resize (gpointer arg)
4881 return ((Editor*)arg)->idle_resize ();
4885 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4887 if (resize_idle_id < 0) {
4888 resize_idle_id = g_idle_add (_idle_resize, this);
4889 _pending_resize_amount = 0;
4892 /* make a note of the smallest resulting height, so that we can clamp the
4893 lower limit at TimeAxisView::hSmall */
4895 int32_t min_resulting = INT32_MAX;
4897 _pending_resize_amount += h;
4898 _pending_resize_view = view;
4900 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4902 if (selection->tracks.contains (_pending_resize_view)) {
4903 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4904 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4908 if (min_resulting < 0) {
4913 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4914 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4918 /** Handle pending resizing of tracks */
4920 Editor::idle_resize ()
4922 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4924 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4925 selection->tracks.contains (_pending_resize_view)) {
4927 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4928 if (*i != _pending_resize_view) {
4929 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4934 _pending_resize_amount = 0;
4936 _group_tabs->set_dirty ();
4937 resize_idle_id = -1;
4945 ENSURE_GUI_THREAD (*this, &Editor::located);
4947 playhead_cursor->set_position (_session->audible_frame ());
4948 if (_follow_playhead && !_pending_initial_locate) {
4949 reset_x_origin_to_follow_playhead ();
4952 _pending_locate_request = false;
4953 _pending_initial_locate = false;
4957 Editor::region_view_added (RegionView *)
4959 _summary->set_dirty ();
4963 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4965 TrackViewList::const_iterator j = track_views.begin ();
4966 while (j != track_views.end()) {
4967 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4968 if (rtv && rtv->route() == r) {
4979 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4983 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4984 TimeAxisView* tv = axis_view_from_route (*i);
4995 Editor::handle_new_route (RouteList& routes)
4997 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4999 RouteTimeAxisView *rtv;
5000 list<RouteTimeAxisView*> new_views;
5002 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5003 boost::shared_ptr<Route> route = (*x);
5005 if (route->is_hidden() || route->is_monitor()) {
5009 DataType dt = route->input()->default_type();
5011 if (dt == ARDOUR::DataType::AUDIO) {
5012 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
5013 } else if (dt == ARDOUR::DataType::MIDI) {
5014 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
5016 throw unknown_type();
5019 new_views.push_back (rtv);
5020 track_views.push_back (rtv);
5022 rtv->effective_gain_display ();
5024 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5027 _routes->routes_added (new_views);
5029 if (show_editor_mixer_when_tracks_arrive) {
5030 show_editor_mixer (true);
5033 editor_list_button.set_sensitive (true);
5035 _summary->set_dirty ();
5039 Editor::timeaxisview_deleted (TimeAxisView *tv)
5041 if (_session && _session->deletion_in_progress()) {
5042 /* the situation is under control */
5046 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5048 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5050 _routes->route_removed (tv);
5052 if (tv == entered_track) {
5056 TimeAxisView::Children c = tv->get_child_list ();
5057 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5058 if (entered_track == i->get()) {
5063 /* remove it from the list of track views */
5065 TrackViewList::iterator i;
5067 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5068 i = track_views.erase (i);
5071 /* update whatever the current mixer strip is displaying, if revelant */
5073 boost::shared_ptr<Route> route;
5076 route = rtav->route ();
5079 if (current_mixer_strip && current_mixer_strip->route() == route) {
5081 TimeAxisView* next_tv;
5083 if (track_views.empty()) {
5085 } else if (i == track_views.end()) {
5086 next_tv = track_views.front();
5093 set_selected_mixer_strip (*next_tv);
5095 /* make the editor mixer strip go away setting the
5096 * button to inactive (which also unticks the menu option)
5099 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5105 Editor::hide_track_in_display (TimeAxisView* tv, bool /*temponly*/)
5107 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5109 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5110 // this will hide the mixer strip
5111 set_selected_mixer_strip (*tv);
5114 _routes->hide_track_in_display (*tv);
5118 Editor::sync_track_view_list_and_routes ()
5120 track_views = TrackViewList (_routes->views ());
5122 _summary->set_dirty ();
5123 _group_tabs->set_dirty ();
5125 return false; // do not call again (until needed)
5129 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5131 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5136 /** Find a RouteTimeAxisView by the ID of its route */
5138 Editor::get_route_view_by_route_id (PBD::ID& id) const
5140 RouteTimeAxisView* v;
5142 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5143 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5144 if(v->route()->id() == id) {
5154 Editor::fit_route_group (RouteGroup *g)
5156 TrackViewList ts = axis_views_from_routes (g->route_list ());
5161 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5163 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5166 _session->cancel_audition ();
5170 if (_session->is_auditioning()) {
5171 _session->cancel_audition ();
5172 if (r == last_audition_region) {
5177 _session->audition_region (r);
5178 last_audition_region = r;
5183 Editor::hide_a_region (boost::shared_ptr<Region> r)
5185 r->set_hidden (true);
5189 Editor::show_a_region (boost::shared_ptr<Region> r)
5191 r->set_hidden (false);
5195 Editor::audition_region_from_region_list ()
5197 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5201 Editor::hide_region_from_region_list ()
5203 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5207 Editor::show_region_in_region_list ()
5209 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5213 Editor::step_edit_status_change (bool yn)
5216 start_step_editing ();
5218 stop_step_editing ();
5223 Editor::start_step_editing ()
5225 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5229 Editor::stop_step_editing ()
5231 step_edit_connection.disconnect ();
5235 Editor::check_step_edit ()
5237 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5238 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5240 mtv->check_step_edit ();
5244 return true; // do it again, till we stop
5248 Editor::horizontal_scroll_left_press ()
5250 ++_scroll_callbacks;
5252 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5253 /* delay the first auto-repeat */
5257 double x = leftmost_position() - current_page_frames() / 5;
5264 /* do hacky auto-repeat */
5265 if (!_scroll_connection.connected ()) {
5266 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_left_press), 100);
5267 _scroll_callbacks = 0;
5274 Editor::horizontal_scroll_left_release ()
5276 _scroll_connection.disconnect ();
5280 Editor::horizontal_scroll_right_press ()
5282 ++_scroll_callbacks;
5284 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5285 /* delay the first auto-repeat */
5289 reset_x_origin (leftmost_position() + current_page_frames() / 5);
5291 /* do hacky auto-repeat */
5292 if (!_scroll_connection.connected ()) {
5293 _scroll_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::horizontal_scroll_right_press), 100);
5294 _scroll_callbacks = 0;
5301 Editor::horizontal_scroll_right_release ()
5303 _scroll_connection.disconnect ();
5306 /** Queue a change for the Editor viewport x origin to follow the playhead */
5308 Editor::reset_x_origin_to_follow_playhead ()
5310 framepos_t const frame = playhead_cursor->current_frame;
5312 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5314 if (_session->transport_speed() < 0) {
5316 if (frame > (current_page_frames() / 2)) {
5317 center_screen (frame-(current_page_frames()/2));
5319 center_screen (current_page_frames()/2);
5324 if (frame < leftmost_frame) {
5327 if (_session->transport_rolling()) {
5328 /* rolling; end up with the playhead at the right of the page */
5329 l = frame - current_page_frames ();
5331 /* not rolling: end up with the playhead 3/4 of the way along the page */
5332 l = frame - (3 * current_page_frames() / 4);
5339 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5342 if (_session->transport_rolling()) {
5343 /* rolling: end up with the playhead on the left of the page */
5344 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5346 /* not rolling: end up with the playhead 1/4 of the way along the page */
5347 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5355 Editor::super_rapid_screen_update ()
5357 if (!_session || !_session->engine().running()) {
5361 /* METERING / MIXER STRIPS */
5363 /* update track meters, if required */
5364 if (is_mapped() && meters_running) {
5365 RouteTimeAxisView* rtv;
5366 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5367 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5368 rtv->fast_update ();
5373 /* and any current mixer strip */
5374 if (current_mixer_strip) {
5375 current_mixer_strip->fast_update ();
5378 /* PLAYHEAD AND VIEWPORT */
5380 framepos_t const frame = _session->audible_frame();
5382 /* There are a few reasons why we might not update the playhead / viewport stuff:
5384 * 1. we don't update things when there's a pending locate request, otherwise
5385 * when the editor requests a locate there is a chance that this method
5386 * will move the playhead before the locate request is processed, causing
5388 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5389 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5392 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5394 last_update_frame = frame;
5396 if (!_dragging_playhead) {
5397 playhead_cursor->set_position (frame);
5400 if (!_stationary_playhead) {
5402 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5403 reset_x_origin_to_follow_playhead ();
5408 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5412 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5413 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5414 if (target <= 0.0) {
5417 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5418 target = (target * 0.15) + (current * 0.85);
5424 set_horizontal_position (current);
5433 Editor::session_going_away ()
5435 _have_idled = false;
5437 _session_connections.drop_connections ();
5439 super_rapid_screen_update_connection.disconnect ();
5441 selection->clear ();
5442 cut_buffer->clear ();
5444 clicked_regionview = 0;
5445 clicked_axisview = 0;
5446 clicked_routeview = 0;
5447 clicked_crossfadeview = 0;
5448 entered_regionview = 0;
5450 last_update_frame = 0;
5453 playhead_cursor->canvas_item.hide ();
5455 /* rip everything out of the list displays */
5459 _route_groups->clear ();
5461 /* do this first so that deleting a track doesn't reset cms to null
5462 and thus cause a leak.
5465 if (current_mixer_strip) {
5466 if (current_mixer_strip->get_parent() != 0) {
5467 global_hpacker.remove (*current_mixer_strip);
5469 delete current_mixer_strip;
5470 current_mixer_strip = 0;
5473 /* delete all trackviews */
5475 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5478 track_views.clear ();
5480 zoom_range_clock.set_session (0);
5481 nudge_clock.set_session (0);
5483 editor_list_button.set_active(false);
5484 editor_list_button.set_sensitive(false);
5486 /* clear tempo/meter rulers */
5487 remove_metric_marks ();
5489 clear_marker_display ();
5491 delete current_bbt_points;
5492 current_bbt_points = 0;
5494 /* get rid of any existing editor mixer strip */
5496 WindowTitle title(Glib::get_application_name());
5497 title += _("Editor");
5499 set_title (title.get_string());
5501 SessionHandlePtr::session_going_away ();
5506 Editor::show_editor_list (bool yn)
5509 the_notebook.show();
5511 the_notebook.hide();
5516 Editor::change_region_layering_order ()
5518 framepos_t const position = get_preferred_edit_position ();
5520 if (!clicked_routeview) {
5521 if (layering_order_editor) {
5522 layering_order_editor->hide ();
5527 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5533 boost::shared_ptr<Playlist> pl = track->playlist();
5539 if (layering_order_editor == 0) {
5540 layering_order_editor = new RegionLayeringOrderEditor(*this);
5543 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5544 layering_order_editor->maybe_present ();
5548 Editor::update_region_layering_order_editor ()
5550 if (layering_order_editor && layering_order_editor->is_visible ()) {
5551 change_region_layering_order ();
5556 Editor::setup_fade_images ()
5558 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5559 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5560 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5561 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5562 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5564 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5565 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5566 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5567 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5568 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5572 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5574 Editor::action_menu_item (std::string const & name)
5576 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5579 return *manage (a->create_menu_item ());