2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <glibmm/uriutils.h>
51 #include <gtkmm/image.h>
52 #include <gdkmm/color.h>
53 #include <gdkmm/bitmap.h>
55 #include <gtkmm/menu.h>
56 #include <gtkmm/menuitem.h>
58 #include "gtkmm2ext/bindings.h"
59 #include "gtkmm2ext/grouped_buttons.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/tearoff.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/choice.h"
65 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/location.h"
71 #include "ardour/profile.h"
72 #include "ardour/route_group.h"
73 #include "ardour/session_playlists.h"
74 #include "ardour/tempo.h"
75 #include "ardour/utils.h"
77 #include "canvas/debug.h"
78 #include "canvas/text.h"
80 #include "control_protocol/control_protocol.h"
84 #include "analysis_window.h"
85 #include "audio_clock.h"
86 #include "audio_region_view.h"
87 #include "audio_streamview.h"
88 #include "audio_time_axis.h"
89 #include "automation_time_axis.h"
90 #include "bundle_manager.h"
91 #include "crossfade_edit.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_time_axis.h"
110 #include "mixer_strip.h"
111 #include "mixer_ui.h"
112 #include "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "tempo_lines.h"
121 #include "time_axis_view.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , videotl_label (_("Video Timeline"))
250 , edit_packer (4, 4, true)
252 /* the values here don't matter: layout widgets
253 reset them as needed.
256 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
257 , horizontal_adjustment (0.0, 0.0, 1e16)
258 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
260 , controls_layout (unused_adjustment, vertical_adjustment)
262 /* tool bar related */
264 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
265 , toolbar_selection_clock_table (2,3)
266 , _mouse_mode_tearoff (0)
267 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
275 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
276 , meters_running(false)
277 , _pending_locate_request (false)
278 , _pending_initial_locate (false)
279 , _last_cut_copy_source_track (0)
281 , _region_selection_change_updates_region_list (true)
282 , _following_mixer_selection (false)
283 , _control_point_toggled_on_press (false)
284 , _stepping_axis_view (0)
288 /* we are a singleton */
290 PublicEditor::_instance = this;
294 selection = new Selection (this);
295 cut_buffer = new Selection (this);
297 clicked_regionview = 0;
298 clicked_axisview = 0;
299 clicked_routeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 build_edit_mode_menu();
317 build_zoom_focus_menu();
318 build_track_count_menu();
319 build_snap_mode_menu();
320 build_snap_type_menu();
321 build_edit_point_menu();
323 snap_threshold = 5.0;
324 bbt_beat_subdivision = 4;
325 _visible_canvas_width = 0;
326 _visible_canvas_height = 0;
327 autoscroll_horizontal_allowed = false;
328 autoscroll_vertical_allowed = false;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
377 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
378 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
379 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
380 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
382 zoom_focus = ZoomFocusLeft;
383 _edit_point = EditAtMouse;
384 _internal_editing = false;
385 current_canvas_cursor = 0;
386 _visible_track_count = 16;
388 samples_per_pixel = 2048; /* too early to use reset_zoom () */
390 _scroll_callbacks = 0;
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorRulerLabel");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorRulerLabel");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorRulerLabel");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorRulerLabel");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorRulerLabel");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorRulerLabel");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 if (Profile->get_trx()) {
434 mark_label.set_text (_("Markers"));
436 mark_label.set_name ("EditorRulerLabel");
437 mark_label.set_size_request (-1, (int)timebar_height);
438 mark_label.set_alignment (1.0, 0.5);
439 mark_label.set_padding (5,0);
441 mark_label.set_no_show_all();
443 cd_mark_label.set_name ("EditorRulerLabel");
444 cd_mark_label.set_size_request (-1, (int)timebar_height);
445 cd_mark_label.set_alignment (1.0, 0.5);
446 cd_mark_label.set_padding (5,0);
447 cd_mark_label.hide();
448 cd_mark_label.set_no_show_all();
450 videotl_bar_height = 4;
451 videotl_label.set_name ("EditorRulerLabel");
452 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
453 videotl_label.set_alignment (1.0, 0.5);
454 videotl_label.set_padding (5,0);
455 videotl_label.hide();
456 videotl_label.set_no_show_all();
458 range_mark_label.set_name ("EditorRulerLabel");
459 range_mark_label.set_size_request (-1, (int)timebar_height);
460 range_mark_label.set_alignment (1.0, 0.5);
461 range_mark_label.set_padding (5,0);
462 range_mark_label.hide();
463 range_mark_label.set_no_show_all();
465 transport_mark_label.set_name ("EditorRulerLabel");
466 transport_mark_label.set_size_request (-1, (int)timebar_height);
467 transport_mark_label.set_alignment (1.0, 0.5);
468 transport_mark_label.set_padding (5,0);
469 transport_mark_label.hide();
470 transport_mark_label.set_no_show_all();
472 initialize_rulers ();
473 initialize_canvas ();
475 _summary = new EditorSummary (this);
477 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
478 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
480 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
482 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
483 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
485 edit_controls_vbox.set_spacing (0);
486 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
487 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
489 HBox* h = manage (new HBox);
490 _group_tabs = new EditorGroupTabs (this);
491 if (!ARDOUR::Profile->get_trx()) {
492 h->pack_start (*_group_tabs, PACK_SHRINK);
494 h->pack_start (edit_controls_vbox);
495 controls_layout.add (*h);
497 controls_layout.set_name ("EditControlsBase");
498 controls_layout.add_events (Gdk::SCROLL_MASK);
499 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
501 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
502 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
504 _cursors = new MouseCursors;
506 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
508 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
509 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
510 pad_line_1->set_outline_color (0xFF0000FF);
516 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
517 time_canvas_vbox.set_size_request (-1, -1);
519 ruler_label_event_box.add (ruler_label_vbox);
520 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
521 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
523 time_bars_event_box.add (time_bars_vbox);
524 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
525 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
527 time_canvas_event_box.add (time_canvas_vbox);
528 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
530 edit_packer.set_col_spacings (0);
531 edit_packer.set_row_spacings (0);
532 edit_packer.set_homogeneous (false);
533 edit_packer.set_border_width (0);
534 edit_packer.set_name ("EditorWindow");
536 /* labels for the rulers */
537 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
538 /* labels for the marker "tracks" (time bars) */
539 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
541 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
543 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
545 edit_packer.attach (*_track_canvas_viewport, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
547 bottom_hbox.set_border_width (2);
548 bottom_hbox.set_spacing (3);
550 _route_groups = new EditorRouteGroups (this);
551 _routes = new EditorRoutes (this);
552 _regions = new EditorRegions (this);
553 _snapshots = new EditorSnapshots (this);
554 _locations = new EditorLocations (this);
556 add_notebook_page (_("Regions"), _regions->widget ());
557 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
558 add_notebook_page (_("Snapshots"), _snapshots->widget ());
559 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
560 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
562 _the_notebook.set_show_tabs (true);
563 _the_notebook.set_scrollable (true);
564 _the_notebook.popup_disable ();
565 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
566 _the_notebook.show_all ();
568 _notebook_shrunk = false;
570 editor_summary_pane.pack1(edit_packer);
572 Button* summary_arrows_left_left = manage (new Button);
573 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
574 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
575 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_left_right = manage (new Button);
578 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
579 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
580 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_left = manage (new VBox);
583 summary_arrows_left->pack_start (*summary_arrows_left_left);
584 summary_arrows_left->pack_start (*summary_arrows_left_right);
586 Button* summary_arrows_right_up = manage (new Button);
587 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
588 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
589 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 Button* summary_arrows_right_down = manage (new Button);
592 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
593 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
594 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
596 VBox* summary_arrows_right = manage (new VBox);
597 summary_arrows_right->pack_start (*summary_arrows_right_up);
598 summary_arrows_right->pack_start (*summary_arrows_right_down);
600 Frame* summary_frame = manage (new Frame);
601 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
603 summary_frame->add (*_summary);
604 summary_frame->show ();
606 _summary_hbox.pack_start (*summary_arrows_left, false, false);
607 _summary_hbox.pack_start (*summary_frame, true, true);
608 _summary_hbox.pack_start (*summary_arrows_right, false, false);
610 if (!ARDOUR::Profile->get_trx()) {
611 editor_summary_pane.pack2 (_summary_hbox);
614 edit_pane.pack1 (editor_summary_pane, true, true);
615 if (!ARDOUR::Profile->get_trx()) {
616 edit_pane.pack2 (_the_notebook, false, true);
619 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
621 /* XXX: editor_summary_pane might need similar to the edit_pane */
623 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
625 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
626 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
628 top_hbox.pack_start (toolbar_frame);
630 HBox *hbox = manage (new HBox);
631 hbox->pack_start (edit_pane, true, true);
633 global_vpacker.pack_start (top_hbox, false, false);
634 global_vpacker.pack_start (*hbox, true, true);
636 global_hpacker.pack_start (global_vpacker, true, true);
638 set_name ("EditorWindow");
639 add_accel_group (ActionManager::ui_manager->get_accel_group());
641 status_bar_hpacker.show ();
643 vpacker.pack_end (status_bar_hpacker, false, false);
644 vpacker.pack_end (global_hpacker, true, true);
646 /* register actions now so that set_state() can find them and set toggles/checks etc */
649 /* when we start using our own keybinding system for the editor, this
650 * will be uncommented
656 set_zoom_focus (zoom_focus);
657 set_visible_track_count (_visible_track_count);
658 _snap_type = SnapToBeat;
659 set_snap_to (_snap_type);
660 _snap_mode = SnapOff;
661 set_snap_mode (_snap_mode);
662 set_mouse_mode (MouseObject, true);
663 pre_internal_mouse_mode = MouseObject;
664 pre_internal_snap_type = _snap_type;
665 pre_internal_snap_mode = _snap_mode;
666 internal_snap_type = _snap_type;
667 internal_snap_mode = _snap_mode;
668 set_edit_point_preference (EditAtMouse, true);
670 _playlist_selector = new PlaylistSelector();
671 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
673 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
677 nudge_forward_button.set_name ("nudge button");
678 // nudge_forward_button.add_elements (ArdourButton::Inset);
679 nudge_forward_button.set_image(::get_icon("nudge_right"));
681 nudge_backward_button.set_name ("nudge button");
682 // nudge_backward_button.add_elements (ArdourButton::Inset);
683 nudge_backward_button.set_image(::get_icon("nudge_left"));
685 fade_context_menu.set_name ("ArdourContextMenu");
687 /* icons, titles, WM stuff */
689 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
690 Glib::RefPtr<Gdk::Pixbuf> icon;
692 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
693 window_icons.push_back (icon);
695 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
696 window_icons.push_back (icon);
698 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
699 window_icons.push_back (icon);
701 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
702 window_icons.push_back (icon);
704 if (!window_icons.empty()) {
705 // set_icon_list (window_icons);
706 set_default_icon_list (window_icons);
709 WindowTitle title(Glib::get_application_name());
710 title += _("Editor");
711 set_title (title.get_string());
712 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
715 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
717 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
718 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
720 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
722 /* allow external control surfaces/protocols to do various things */
724 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
725 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
726 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
727 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
728 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
729 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
730 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
731 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
732 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
733 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
734 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
735 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
736 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
737 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
739 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
740 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
741 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
742 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
743 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
745 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
747 /* problematic: has to return a value and thus cannot be x-thread */
749 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
751 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
753 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
755 _ignore_region_action = false;
756 _last_region_menu_was_main = false;
757 _popup_region_menu_item = 0;
759 _show_marker_lines = false;
760 _over_region_trim_target = false;
762 /* Button bindings */
764 button_bindings = new Bindings;
766 XMLNode* node = button_settings();
768 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
769 button_bindings->load (**i);
776 setup_fade_images ();
781 delete button_bindings;
783 delete _route_groups;
784 delete _track_canvas_viewport;
789 Editor::button_settings () const
791 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
792 XMLNode* node = find_named_node (*settings, X_("Buttons"));
795 node = new XMLNode (X_("Buttons"));
802 Editor::add_toplevel_controls (Container& cont)
804 vpacker.pack_start (cont, false, false);
809 Editor::get_smart_mode () const
811 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
815 Editor::catch_vanishing_regionview (RegionView *rv)
817 /* note: the selection will take care of the vanishing
818 audioregionview by itself.
821 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
825 if (clicked_regionview == rv) {
826 clicked_regionview = 0;
829 if (entered_regionview == rv) {
830 set_entered_regionview (0);
833 if (!_all_region_actions_sensitized) {
834 sensitize_all_region_actions (true);
837 _over_region_trim_target = false;
841 Editor::set_entered_regionview (RegionView* rv)
843 if (rv == entered_regionview) {
847 if (entered_regionview) {
848 entered_regionview->exited ();
851 if ((entered_regionview = rv) != 0) {
852 entered_regionview->entered (internal_editing ());
855 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
856 /* This RegionView entry might have changed what region actions
857 are allowed, so sensitize them all in case a key is pressed.
859 sensitize_all_region_actions (true);
864 Editor::set_entered_track (TimeAxisView* tav)
867 entered_track->exited ();
870 if ((entered_track = tav) != 0) {
871 entered_track->entered ();
876 Editor::show_window ()
878 if (!is_visible ()) {
881 /* XXX: this is a bit unfortunate; it would probably
882 be nicer if we could just call show () above rather
883 than needing the show_all ()
886 /* re-hide stuff if necessary */
887 editor_list_button_toggled ();
888 parameter_changed ("show-summary");
889 parameter_changed ("show-group-tabs");
890 parameter_changed ("show-zoom-tools");
892 /* now reset all audio_time_axis heights, because widgets might need
898 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
899 tv = (static_cast<TimeAxisView*>(*i));
903 if (current_mixer_strip) {
904 current_mixer_strip->hide_things ();
905 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
913 Editor::instant_save ()
915 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
920 _session->add_instant_xml(get_state());
922 Config->add_instant_xml(get_state());
927 Editor::zoom_adjustment_changed ()
933 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
934 bool clamped = clamp_samples_per_pixel (fpu);
937 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
944 Editor::control_vertical_zoom_in_all ()
946 tav_zoom_smooth (false, true);
950 Editor::control_vertical_zoom_out_all ()
952 tav_zoom_smooth (true, true);
956 Editor::control_vertical_zoom_in_selected ()
958 tav_zoom_smooth (false, false);
962 Editor::control_vertical_zoom_out_selected ()
964 tav_zoom_smooth (true, false);
968 Editor::control_view (uint32_t view)
970 goto_visual_state (view);
974 Editor::control_unselect ()
976 selection->clear_tracks ();
980 Editor::control_select (uint32_t rid, Selection::Operation op)
982 /* handles the (static) signal from the ControlProtocol class that
983 * requests setting the selected track to a given RID
990 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
996 TimeAxisView* tav = axis_view_from_route (r);
1000 case Selection::Add:
1001 selection->add (tav);
1003 case Selection::Toggle:
1004 selection->toggle (tav);
1006 case Selection::Extend:
1008 case Selection::Set:
1009 selection->set (tav);
1013 selection->clear_tracks ();
1018 Editor::control_step_tracks_up ()
1020 scroll_tracks_up_line ();
1024 Editor::control_step_tracks_down ()
1026 scroll_tracks_down_line ();
1030 Editor::control_scroll (float fraction)
1032 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1038 double step = fraction * current_page_samples();
1041 _control_scroll_target is an optional<T>
1043 it acts like a pointer to an framepos_t, with
1044 a operator conversion to boolean to check
1045 that it has a value could possibly use
1046 playhead_cursor->current_frame to store the
1047 value and a boolean in the class to know
1048 when it's out of date
1051 if (!_control_scroll_target) {
1052 _control_scroll_target = _session->transport_frame();
1053 _dragging_playhead = true;
1056 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1057 *_control_scroll_target = 0;
1058 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1059 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1061 *_control_scroll_target += (framepos_t) floor (step);
1064 /* move visuals, we'll catch up with it later */
1066 playhead_cursor->set_position (*_control_scroll_target);
1067 UpdateAllTransportClocks (*_control_scroll_target);
1069 if (*_control_scroll_target > (current_page_samples() / 2)) {
1070 /* try to center PH in window */
1071 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1077 Now we do a timeout to actually bring the session to the right place
1078 according to the playhead. This is to avoid reading disk buffers on every
1079 call to control_scroll, which is driven by ScrollTimeline and therefore
1080 probably by a control surface wheel which can generate lots of events.
1082 /* cancel the existing timeout */
1084 control_scroll_connection.disconnect ();
1086 /* add the next timeout */
1088 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1092 Editor::deferred_control_scroll (framepos_t /*target*/)
1094 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1095 // reset for next stream
1096 _control_scroll_target = boost::none;
1097 _dragging_playhead = false;
1102 Editor::access_action (std::string action_group, std::string action_item)
1108 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1111 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1119 Editor::on_realize ()
1121 Window::on_realize ();
1126 Editor::map_position_change (framepos_t frame)
1128 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1130 if (_session == 0) {
1134 if (_follow_playhead) {
1135 center_screen (frame);
1138 playhead_cursor->set_position (frame);
1142 Editor::center_screen (framepos_t frame)
1144 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1146 /* if we're off the page, then scroll.
1149 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1150 center_screen_internal (frame, page);
1155 Editor::center_screen_internal (framepos_t frame, float page)
1160 frame -= (framepos_t) page;
1165 reset_x_origin (frame);
1170 Editor::update_title ()
1172 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1175 bool dirty = _session->dirty();
1177 string session_name;
1179 if (_session->snap_name() != _session->name()) {
1180 session_name = _session->snap_name();
1182 session_name = _session->name();
1186 session_name = "*" + session_name;
1189 WindowTitle title(session_name);
1190 title += Glib::get_application_name();
1191 set_title (title.get_string());
1193 /* ::session_going_away() will have taken care of it */
1198 Editor::set_session (Session *t)
1200 SessionHandlePtr::set_session (t);
1206 zoom_range_clock->set_session (_session);
1207 _playlist_selector->set_session (_session);
1208 nudge_clock->set_session (_session);
1209 _summary->set_session (_session);
1210 _group_tabs->set_session (_session);
1211 _route_groups->set_session (_session);
1212 _regions->set_session (_session);
1213 _snapshots->set_session (_session);
1214 _routes->set_session (_session);
1215 _locations->set_session (_session);
1217 if (rhythm_ferret) {
1218 rhythm_ferret->set_session (_session);
1221 if (analysis_window) {
1222 analysis_window->set_session (_session);
1226 sfbrowser->set_session (_session);
1229 compute_fixed_ruler_scale ();
1231 /* Make sure we have auto loop and auto punch ranges */
1233 Location* loc = _session->locations()->auto_loop_location();
1235 loc->set_name (_("Loop"));
1238 loc = _session->locations()->auto_punch_location();
1241 loc->set_name (_("Punch"));
1244 refresh_location_display ();
1246 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1247 the selected Marker; this needs the LocationMarker list to be available.
1249 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1250 set_state (*node, Stateful::loading_state_version);
1252 /* catch up with the playhead */
1254 _session->request_locate (playhead_cursor->current_frame ());
1255 _pending_initial_locate = true;
1259 /* These signals can all be emitted by a non-GUI thread. Therefore the
1260 handlers for them must not attempt to directly interact with the GUI,
1261 but use PBD::Signal<T>::connect() which accepts an event loop
1262 ("context") where the handler will be asked to run.
1265 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1266 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1267 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1268 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1269 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1270 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1271 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1272 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1273 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1274 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1275 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1276 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1277 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1278 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1280 playhead_cursor->show ();
1282 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1283 Config->map_parameters (pc);
1284 _session->config.map_parameters (pc);
1286 restore_ruler_visibility ();
1287 //tempo_map_changed (PropertyChange (0));
1288 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1290 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1291 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1294 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1295 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1298 switch (_snap_type) {
1299 case SnapToRegionStart:
1300 case SnapToRegionEnd:
1301 case SnapToRegionSync:
1302 case SnapToRegionBoundary:
1303 build_region_boundary_cache ();
1310 /* register for undo history */
1311 _session->register_with_memento_command_factory(id(), this);
1313 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1315 start_updating_meters ();
1319 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1321 if (a->get_name() == "RegionMenu") {
1322 /* When the main menu's region menu is opened, we setup the actions so that they look right
1323 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1324 so we resensitize all region actions when the entered regionview or the region selection
1325 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1326 happens after the region context menu is opened. So we set a flag here, too.
1330 sensitize_the_right_region_actions ();
1331 _last_region_menu_was_main = true;
1336 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1338 using namespace Menu_Helpers;
1340 void (Editor::*emf)(FadeShape);
1341 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1344 images = &_xfade_in_images;
1345 emf = &Editor::set_fade_in_shape;
1347 images = &_xfade_out_images;
1348 emf = &Editor::set_fade_out_shape;
1353 _("Linear (for highly correlated material)"),
1354 *(*images)[FadeLinear],
1355 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1359 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1363 _("Constant power"),
1364 *(*images)[FadeConstantPower],
1365 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1368 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 *(*images)[FadeSymmetric],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 *(*images)[FadeSlow],
1384 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeFast],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1396 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 /** Pop up a context menu for when the user clicks on a start crossfade */
1401 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1403 using namespace Menu_Helpers;
1404 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1407 MenuList& items (xfade_in_context_menu.items());
1410 if (arv->audio_region()->fade_in_active()) {
1411 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1413 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1416 items.push_back (SeparatorElem());
1417 fill_xfade_menu (items, true);
1419 xfade_in_context_menu.popup (button, time);
1422 /** Pop up a context menu for when the user clicks on an end crossfade */
1424 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1426 using namespace Menu_Helpers;
1427 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1430 MenuList& items (xfade_out_context_menu.items());
1433 if (arv->audio_region()->fade_out_active()) {
1434 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1436 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1439 items.push_back (SeparatorElem());
1440 fill_xfade_menu (items, false);
1442 xfade_out_context_menu.popup (button, time);
1446 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1448 using namespace Menu_Helpers;
1449 Menu* (Editor::*build_menu_function)();
1452 switch (item_type) {
1454 case RegionViewName:
1455 case RegionViewNameHighlight:
1456 case LeftFrameHandle:
1457 case RightFrameHandle:
1458 if (with_selection) {
1459 build_menu_function = &Editor::build_track_selection_context_menu;
1461 build_menu_function = &Editor::build_track_region_context_menu;
1466 if (with_selection) {
1467 build_menu_function = &Editor::build_track_selection_context_menu;
1469 build_menu_function = &Editor::build_track_context_menu;
1474 if (clicked_routeview->track()) {
1475 build_menu_function = &Editor::build_track_context_menu;
1477 build_menu_function = &Editor::build_track_bus_context_menu;
1482 /* probably shouldn't happen but if it does, we don't care */
1486 menu = (this->*build_menu_function)();
1487 menu->set_name ("ArdourContextMenu");
1489 /* now handle specific situations */
1491 switch (item_type) {
1493 case RegionViewName:
1494 case RegionViewNameHighlight:
1495 case LeftFrameHandle:
1496 case RightFrameHandle:
1497 if (!with_selection) {
1498 if (region_edit_menu_split_item) {
1499 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1500 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1502 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1505 if (region_edit_menu_split_multichannel_item) {
1506 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1507 region_edit_menu_split_multichannel_item->set_sensitive (true);
1509 region_edit_menu_split_multichannel_item->set_sensitive (false);
1522 /* probably shouldn't happen but if it does, we don't care */
1526 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1528 /* Bounce to disk */
1530 using namespace Menu_Helpers;
1531 MenuList& edit_items = menu->items();
1533 edit_items.push_back (SeparatorElem());
1535 switch (clicked_routeview->audio_track()->freeze_state()) {
1536 case AudioTrack::NoFreeze:
1537 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1540 case AudioTrack::Frozen:
1541 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1544 case AudioTrack::UnFrozen:
1545 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1551 if (item_type == StreamItem && clicked_routeview) {
1552 clicked_routeview->build_underlay_menu(menu);
1555 /* When the region menu is opened, we setup the actions so that they look right
1558 sensitize_the_right_region_actions ();
1559 _last_region_menu_was_main = false;
1561 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1562 menu->popup (button, time);
1566 Editor::build_track_context_menu ()
1568 using namespace Menu_Helpers;
1570 MenuList& edit_items = track_context_menu.items();
1573 add_dstream_context_items (edit_items);
1574 return &track_context_menu;
1578 Editor::build_track_bus_context_menu ()
1580 using namespace Menu_Helpers;
1582 MenuList& edit_items = track_context_menu.items();
1585 add_bus_context_items (edit_items);
1586 return &track_context_menu;
1590 Editor::build_track_region_context_menu ()
1592 using namespace Menu_Helpers;
1593 MenuList& edit_items = track_region_context_menu.items();
1596 /* we've just cleared the track region context menu, so the menu that these
1597 two items were on will have disappeared; stop them dangling.
1599 region_edit_menu_split_item = 0;
1600 region_edit_menu_split_multichannel_item = 0;
1602 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1605 boost::shared_ptr<Track> tr;
1606 boost::shared_ptr<Playlist> pl;
1608 if ((tr = rtv->track())) {
1609 add_region_context_items (edit_items, tr);
1613 add_dstream_context_items (edit_items);
1615 return &track_region_context_menu;
1619 Editor::analyze_region_selection ()
1621 if (analysis_window == 0) {
1622 analysis_window = new AnalysisWindow();
1625 analysis_window->set_session(_session);
1627 analysis_window->show_all();
1630 analysis_window->set_regionmode();
1631 analysis_window->analyze();
1633 analysis_window->present();
1637 Editor::analyze_range_selection()
1639 if (analysis_window == 0) {
1640 analysis_window = new AnalysisWindow();
1643 analysis_window->set_session(_session);
1645 analysis_window->show_all();
1648 analysis_window->set_rangemode();
1649 analysis_window->analyze();
1651 analysis_window->present();
1655 Editor::build_track_selection_context_menu ()
1657 using namespace Menu_Helpers;
1658 MenuList& edit_items = track_selection_context_menu.items();
1659 edit_items.clear ();
1661 add_selection_context_items (edit_items);
1662 // edit_items.push_back (SeparatorElem());
1663 // add_dstream_context_items (edit_items);
1665 return &track_selection_context_menu;
1669 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1671 using namespace Menu_Helpers;
1673 /* OK, stick the region submenu at the top of the list, and then add
1677 RegionSelection rs = get_regions_from_selection_and_entered ();
1679 string::size_type pos = 0;
1680 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1682 /* we have to hack up the region name because "_" has a special
1683 meaning for menu titles.
1686 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1687 menu_item_name.replace (pos, 1, "__");
1691 if (_popup_region_menu_item == 0) {
1692 _popup_region_menu_item = new MenuItem (menu_item_name);
1693 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1694 _popup_region_menu_item->show ();
1696 _popup_region_menu_item->set_label (menu_item_name);
1699 const framepos_t position = get_preferred_edit_position (false, true);
1701 edit_items.push_back (*_popup_region_menu_item);
1702 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1703 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1705 edit_items.push_back (SeparatorElem());
1708 /** Add context menu items relevant to selection ranges.
1709 * @param edit_items List to add the items to.
1712 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1714 using namespace Menu_Helpers;
1716 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1717 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1719 edit_items.push_back (SeparatorElem());
1720 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1722 edit_items.push_back (SeparatorElem());
1724 edit_items.push_back (
1726 _("Move Range Start to Previous Region Boundary"),
1727 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1731 edit_items.push_back (
1733 _("Move Range Start to Next Region Boundary"),
1734 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1738 edit_items.push_back (
1740 _("Move Range End to Previous Region Boundary"),
1741 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1745 edit_items.push_back (
1747 _("Move Range End to Next Region Boundary"),
1748 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1752 edit_items.push_back (SeparatorElem());
1753 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1754 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1756 edit_items.push_back (SeparatorElem());
1757 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1759 edit_items.push_back (SeparatorElem());
1760 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1761 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1763 edit_items.push_back (SeparatorElem());
1764 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1766 edit_items.push_back (SeparatorElem());
1767 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1768 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1769 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1771 edit_items.push_back (SeparatorElem());
1772 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1773 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1774 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1775 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1776 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1777 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1778 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1784 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1786 using namespace Menu_Helpers;
1790 Menu *play_menu = manage (new Menu);
1791 MenuList& play_items = play_menu->items();
1792 play_menu->set_name ("ArdourContextMenu");
1794 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1795 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1796 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1797 play_items.push_back (SeparatorElem());
1798 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1800 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1804 Menu *select_menu = manage (new Menu);
1805 MenuList& select_items = select_menu->items();
1806 select_menu->set_name ("ArdourContextMenu");
1808 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1809 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1810 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1811 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1812 select_items.push_back (SeparatorElem());
1813 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1814 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1815 select_items.push_back (SeparatorElem());
1816 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1817 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1818 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1819 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1820 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1821 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1822 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1824 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1828 Menu *cutnpaste_menu = manage (new Menu);
1829 MenuList& cutnpaste_items = cutnpaste_menu->items();
1830 cutnpaste_menu->set_name ("ArdourContextMenu");
1832 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1833 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1834 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1836 cutnpaste_items.push_back (SeparatorElem());
1838 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1839 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1841 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1843 /* Adding new material */
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1847 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1851 Menu *nudge_menu = manage (new Menu());
1852 MenuList& nudge_items = nudge_menu->items();
1853 nudge_menu->set_name ("ArdourContextMenu");
1855 edit_items.push_back (SeparatorElem());
1856 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1857 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1858 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1859 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1861 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1865 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1867 using namespace Menu_Helpers;
1871 Menu *play_menu = manage (new Menu);
1872 MenuList& play_items = play_menu->items();
1873 play_menu->set_name ("ArdourContextMenu");
1875 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1876 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1877 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1881 Menu *select_menu = manage (new Menu);
1882 MenuList& select_items = select_menu->items();
1883 select_menu->set_name ("ArdourContextMenu");
1885 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1886 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1887 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1888 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1889 select_items.push_back (SeparatorElem());
1890 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1891 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1892 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1893 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1895 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1899 Menu *cutnpaste_menu = manage (new Menu);
1900 MenuList& cutnpaste_items = cutnpaste_menu->items();
1901 cutnpaste_menu->set_name ("ArdourContextMenu");
1903 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1904 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1905 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1907 Menu *nudge_menu = manage (new Menu());
1908 MenuList& nudge_items = nudge_menu->items();
1909 nudge_menu->set_name ("ArdourContextMenu");
1911 edit_items.push_back (SeparatorElem());
1912 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1913 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1914 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1915 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1917 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1921 Editor::snap_type() const
1927 Editor::snap_mode() const
1933 Editor::set_snap_to (SnapType st)
1935 unsigned int snap_ind = (unsigned int)st;
1939 if (snap_ind > snap_type_strings.size() - 1) {
1941 _snap_type = (SnapType)snap_ind;
1944 string str = snap_type_strings[snap_ind];
1946 if (str != snap_type_selector.get_text()) {
1947 snap_type_selector.set_text (str);
1952 switch (_snap_type) {
1953 case SnapToBeatDiv128:
1954 case SnapToBeatDiv64:
1955 case SnapToBeatDiv32:
1956 case SnapToBeatDiv28:
1957 case SnapToBeatDiv24:
1958 case SnapToBeatDiv20:
1959 case SnapToBeatDiv16:
1960 case SnapToBeatDiv14:
1961 case SnapToBeatDiv12:
1962 case SnapToBeatDiv10:
1963 case SnapToBeatDiv8:
1964 case SnapToBeatDiv7:
1965 case SnapToBeatDiv6:
1966 case SnapToBeatDiv5:
1967 case SnapToBeatDiv4:
1968 case SnapToBeatDiv3:
1969 case SnapToBeatDiv2: {
1970 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
1971 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
1973 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
1974 current_bbt_points_begin, current_bbt_points_end);
1975 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
1976 current_bbt_points_begin, current_bbt_points_end);
1977 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
1981 case SnapToRegionStart:
1982 case SnapToRegionEnd:
1983 case SnapToRegionSync:
1984 case SnapToRegionBoundary:
1985 build_region_boundary_cache ();
1993 SnapChanged (); /* EMIT SIGNAL */
1997 Editor::set_snap_mode (SnapMode mode)
1999 string str = snap_mode_strings[(int)mode];
2001 if (_internal_editing) {
2002 internal_snap_mode = mode;
2004 pre_internal_snap_mode = mode;
2009 if (str != snap_mode_selector.get_text ()) {
2010 snap_mode_selector.set_text (str);
2016 Editor::set_edit_point_preference (EditPoint ep, bool force)
2018 bool changed = (_edit_point != ep);
2021 string str = edit_point_strings[(int)ep];
2023 if (str != edit_point_selector.get_text ()) {
2024 edit_point_selector.set_text (str);
2027 set_canvas_cursor ();
2029 if (!force && !changed) {
2033 const char* action=NULL;
2035 switch (_edit_point) {
2036 case EditAtPlayhead:
2037 action = "edit-at-playhead";
2039 case EditAtSelectedMarker:
2040 action = "edit-at-marker";
2043 action = "edit-at-mouse";
2047 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2049 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2053 bool in_track_canvas;
2055 if (!mouse_frame (foo, in_track_canvas)) {
2056 in_track_canvas = false;
2059 reset_canvas_action_sensitivity (in_track_canvas);
2065 Editor::set_state (const XMLNode& node, int /*version*/)
2067 const XMLProperty* prop;
2074 g.base_width = default_width;
2075 g.base_height = default_height;
2079 if ((geometry = find_named_node (node, "geometry")) != 0) {
2083 if ((prop = geometry->property("x_size")) == 0) {
2084 prop = geometry->property ("x-size");
2087 g.base_width = atoi(prop->value());
2089 if ((prop = geometry->property("y_size")) == 0) {
2090 prop = geometry->property ("y-size");
2093 g.base_height = atoi(prop->value());
2096 if ((prop = geometry->property ("x_pos")) == 0) {
2097 prop = geometry->property ("x-pos");
2100 x = atoi (prop->value());
2103 if ((prop = geometry->property ("y_pos")) == 0) {
2104 prop = geometry->property ("y-pos");
2107 y = atoi (prop->value());
2111 set_default_size (g.base_width, g.base_height);
2114 if (_session && (prop = node.property ("playhead"))) {
2116 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2117 playhead_cursor->set_position (pos);
2119 playhead_cursor->set_position (0);
2122 if ((prop = node.property ("mixer-width"))) {
2123 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2126 if ((prop = node.property ("zoom-focus"))) {
2127 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2130 if ((prop = node.property ("zoom"))) {
2131 /* older versions of ardour used floating point samples_per_pixel */
2132 double f = PBD::atof (prop->value());
2133 reset_zoom (llrintf (f));
2135 reset_zoom (samples_per_pixel);
2138 if ((prop = node.property ("visible-track-count"))) {
2139 set_visible_track_count (PBD::atoi (prop->value()));
2142 if ((prop = node.property ("snap-to"))) {
2143 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2146 if ((prop = node.property ("snap-mode"))) {
2147 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2150 if ((prop = node.property ("internal-snap-to"))) {
2151 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2154 if ((prop = node.property ("internal-snap-mode"))) {
2155 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2158 if ((prop = node.property ("pre-internal-snap-to"))) {
2159 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2163 if ((prop = node.property ("pre-internal-snap-mode"))) {
2164 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2167 if ((prop = node.property ("mouse-mode"))) {
2168 MouseMode m = str2mousemode(prop->value());
2169 set_mouse_mode (m, true);
2171 set_mouse_mode (MouseObject, true);
2174 if ((prop = node.property ("left-frame")) != 0) {
2176 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2180 reset_x_origin (pos);
2184 if ((prop = node.property ("y-origin")) != 0) {
2185 reset_y_origin (atof (prop->value ()));
2188 if ((prop = node.property ("internal-edit"))) {
2189 bool yn = string_is_affirmative (prop->value());
2190 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2192 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2193 tact->set_active (!yn);
2194 tact->set_active (yn);
2198 if ((prop = node.property ("join-object-range"))) {
2199 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2200 bool yn = string_is_affirmative (prop->value());
2202 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2203 tact->set_active (!yn);
2204 tact->set_active (yn);
2206 set_mouse_mode(mouse_mode, true);
2209 if ((prop = node.property ("edit-point"))) {
2210 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2213 if ((prop = node.property ("show-measures"))) {
2214 bool yn = string_is_affirmative (prop->value());
2215 _show_measures = yn;
2216 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2218 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2219 /* do it twice to force the change */
2220 tact->set_active (!yn);
2221 tact->set_active (yn);
2225 if ((prop = node.property ("follow-playhead"))) {
2226 bool yn = string_is_affirmative (prop->value());
2227 set_follow_playhead (yn);
2228 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2230 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2231 if (tact->get_active() != yn) {
2232 tact->set_active (yn);
2237 if ((prop = node.property ("stationary-playhead"))) {
2238 bool yn = string_is_affirmative (prop->value());
2239 set_stationary_playhead (yn);
2240 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2242 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2243 if (tact->get_active() != yn) {
2244 tact->set_active (yn);
2249 if ((prop = node.property ("region-list-sort-type"))) {
2250 RegionListSortType st;
2251 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2254 if ((prop = node.property ("show-editor-mixer"))) {
2256 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2259 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2260 bool yn = string_is_affirmative (prop->value());
2262 /* do it twice to force the change */
2264 tact->set_active (!yn);
2265 tact->set_active (yn);
2268 if ((prop = node.property ("show-editor-list"))) {
2270 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2273 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2274 bool yn = string_is_affirmative (prop->value());
2276 /* do it twice to force the change */
2278 tact->set_active (!yn);
2279 tact->set_active (yn);
2282 if ((prop = node.property (X_("editor-list-page")))) {
2283 _the_notebook.set_current_page (atoi (prop->value ()));
2286 if ((prop = node.property (X_("show-marker-lines")))) {
2287 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2289 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2290 bool yn = string_is_affirmative (prop->value ());
2292 tact->set_active (!yn);
2293 tact->set_active (yn);
2296 XMLNodeList children = node.children ();
2297 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2298 selection->set_state (**i, Stateful::current_state_version);
2299 _regions->set_state (**i);
2302 if ((prop = node.property ("maximised"))) {
2303 bool yn = string_is_affirmative (prop->value());
2304 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2306 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2307 bool fs = tact && tact->get_active();
2309 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2313 if ((prop = node.property ("nudge-clock-value"))) {
2315 sscanf (prop->value().c_str(), "%" PRId64, &f);
2316 nudge_clock->set (f);
2318 nudge_clock->set_mode (AudioClock::Timecode);
2319 nudge_clock->set (_session->frame_rate() * 5, true);
2326 Editor::get_state ()
2328 XMLNode* node = new XMLNode ("Editor");
2331 id().print (buf, sizeof (buf));
2332 node->add_property ("id", buf);
2334 if (is_realized()) {
2335 Glib::RefPtr<Gdk::Window> win = get_window();
2337 int x, y, width, height;
2338 win->get_root_origin(x, y);
2339 win->get_size(width, height);
2341 XMLNode* geometry = new XMLNode ("geometry");
2343 snprintf(buf, sizeof(buf), "%d", width);
2344 geometry->add_property("x-size", string(buf));
2345 snprintf(buf, sizeof(buf), "%d", height);
2346 geometry->add_property("y-size", string(buf));
2347 snprintf(buf, sizeof(buf), "%d", x);
2348 geometry->add_property("x-pos", string(buf));
2349 snprintf(buf, sizeof(buf), "%d", y);
2350 geometry->add_property("y-pos", string(buf));
2351 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2352 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2353 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2354 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2355 geometry->add_property("edit-vertical-pane-pos", string(buf));
2357 node->add_child_nocopy (*geometry);
2360 maybe_add_mixer_strip_width (*node);
2362 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2364 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2365 node->add_property ("zoom", buf);
2366 node->add_property ("snap-to", enum_2_string (_snap_type));
2367 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2368 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2369 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2370 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2371 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2372 node->add_property ("edit-point", enum_2_string (_edit_point));
2373 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2374 node->add_property ("visible-track-count", buf);
2376 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2377 node->add_property ("playhead", buf);
2378 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2379 node->add_property ("left-frame", buf);
2380 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2381 node->add_property ("y-origin", buf);
2383 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2384 node->add_property ("maximised", _maximised ? "yes" : "no");
2385 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2386 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2387 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2388 node->add_property ("mouse-mode", enum2str(mouse_mode));
2389 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2390 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2392 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2394 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2395 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2398 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2404 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2405 node->add_property (X_("editor-list-page"), buf);
2407 if (button_bindings) {
2408 XMLNode* bb = new XMLNode (X_("Buttons"));
2409 button_bindings->save (*bb);
2410 node->add_child_nocopy (*bb);
2413 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2415 node->add_child_nocopy (selection->get_state ());
2416 node->add_child_nocopy (_regions->get_state ());
2418 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2419 node->add_property ("nudge-clock-value", buf);
2424 /** @param y y is an offset into the trackview area, in pixel units
2426 * @return pair: TimeAxisView that y is over, layer index.
2428 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2429 * in stacked or expanded region display mode, otherwise 0.
2431 std::pair<TimeAxisView *, double>
2432 Editor::trackview_by_y_position (double y)
2435 return std::make_pair ( (TimeAxisView *) 0, 0);
2438 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2440 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2448 /** Snap a position to the grid, if appropriate, taking into account current
2449 * grid settings and also the state of any snap modifier keys that may be pressed.
2450 * @param start Position to snap.
2451 * @param event Event to get current key modifier information from, or 0.
2454 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2456 if (!_session || !event) {
2460 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2461 if (_snap_mode == SnapOff) {
2462 snap_to_internal (start, direction, for_mark);
2465 if (_snap_mode != SnapOff) {
2466 snap_to_internal (start, direction, for_mark);
2472 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2474 if (!_session || _snap_mode == SnapOff) {
2478 snap_to_internal (start, direction, for_mark);
2482 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2484 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2485 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2487 switch (_snap_type) {
2488 case SnapToTimecodeFrame:
2489 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2490 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2492 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2496 case SnapToTimecodeSeconds:
2497 if (_session->config.get_timecode_offset_negative()) {
2498 start += _session->config.get_timecode_offset ();
2500 start -= _session->config.get_timecode_offset ();
2502 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2503 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2505 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2508 if (_session->config.get_timecode_offset_negative()) {
2509 start -= _session->config.get_timecode_offset ();
2511 start += _session->config.get_timecode_offset ();
2515 case SnapToTimecodeMinutes:
2516 if (_session->config.get_timecode_offset_negative()) {
2517 start += _session->config.get_timecode_offset ();
2519 start -= _session->config.get_timecode_offset ();
2521 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2522 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2524 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2526 if (_session->config.get_timecode_offset_negative()) {
2527 start -= _session->config.get_timecode_offset ();
2529 start += _session->config.get_timecode_offset ();
2533 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2539 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2541 const framepos_t one_second = _session->frame_rate();
2542 const framepos_t one_minute = _session->frame_rate() * 60;
2543 framepos_t presnap = start;
2547 switch (_snap_type) {
2548 case SnapToTimecodeFrame:
2549 case SnapToTimecodeSeconds:
2550 case SnapToTimecodeMinutes:
2551 return timecode_snap_to_internal (start, direction, for_mark);
2554 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2555 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2557 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2562 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2563 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2565 start = (framepos_t) floor ((double) start / one_second) * one_second;
2570 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2571 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2573 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2578 start = _session->tempo_map().round_to_bar (start, direction);
2582 start = _session->tempo_map().round_to_beat (start, direction);
2585 case SnapToBeatDiv128:
2586 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2588 case SnapToBeatDiv64:
2589 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2591 case SnapToBeatDiv32:
2592 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2594 case SnapToBeatDiv28:
2595 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2597 case SnapToBeatDiv24:
2598 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2600 case SnapToBeatDiv20:
2601 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2603 case SnapToBeatDiv16:
2604 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2606 case SnapToBeatDiv14:
2607 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2609 case SnapToBeatDiv12:
2610 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2612 case SnapToBeatDiv10:
2613 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2615 case SnapToBeatDiv8:
2616 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2618 case SnapToBeatDiv7:
2619 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2621 case SnapToBeatDiv6:
2622 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2624 case SnapToBeatDiv5:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2627 case SnapToBeatDiv4:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2630 case SnapToBeatDiv3:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2633 case SnapToBeatDiv2:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2642 _session->locations()->marks_either_side (start, before, after);
2644 if (before == max_framepos && after == max_framepos) {
2645 /* No marks to snap to, so just don't snap */
2647 } else if (before == max_framepos) {
2649 } else if (after == max_framepos) {
2651 } else if (before != max_framepos && after != max_framepos) {
2652 /* have before and after */
2653 if ((start - before) < (after - start)) {
2662 case SnapToRegionStart:
2663 case SnapToRegionEnd:
2664 case SnapToRegionSync:
2665 case SnapToRegionBoundary:
2666 if (!region_boundary_cache.empty()) {
2668 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2669 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2671 if (direction > 0) {
2672 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2674 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2677 if (next != region_boundary_cache.begin ()) {
2682 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2683 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2685 if (start > (p + n) / 2) {
2694 switch (_snap_mode) {
2700 if (presnap > start) {
2701 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2705 } else if (presnap < start) {
2706 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2712 /* handled at entry */
2720 Editor::setup_toolbar ()
2722 HBox* mode_box = manage(new HBox);
2723 mode_box->set_border_width (2);
2724 mode_box->set_spacing(4);
2726 HBox* mouse_mode_box = manage (new HBox);
2727 HBox* mouse_mode_hbox = manage (new HBox);
2728 VBox* mouse_mode_vbox = manage (new VBox);
2729 Alignment* mouse_mode_align = manage (new Alignment);
2731 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2732 // mouse_mode_size_group->add_widget (smart_mode_button);
2733 mouse_mode_size_group->add_widget (mouse_move_button);
2734 mouse_mode_size_group->add_widget (mouse_select_button);
2735 mouse_mode_size_group->add_widget (mouse_zoom_button);
2736 mouse_mode_size_group->add_widget (mouse_gain_button);
2737 mouse_mode_size_group->add_widget (mouse_timefx_button);
2738 mouse_mode_size_group->add_widget (mouse_audition_button);
2739 mouse_mode_size_group->add_widget (mouse_draw_button);
2740 mouse_mode_size_group->add_widget (internal_edit_button);
2742 /* make them just a bit bigger */
2743 mouse_move_button.set_size_request (-1, 30);
2745 mouse_mode_hbox->set_spacing (2);
2747 if (!ARDOUR::Profile->get_trx()) {
2748 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2751 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2752 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2753 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2755 if (!ARDOUR::Profile->get_trx()) {
2756 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2757 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2758 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2759 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2760 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2763 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2765 mouse_mode_align->add (*mouse_mode_vbox);
2766 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2768 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2770 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2771 if (!Profile->get_sae()) {
2772 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2774 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2776 edit_mode_selector.set_name ("mouse mode button");
2777 edit_mode_selector.set_size_request (65, -1);
2778 edit_mode_selector.add_elements (ArdourButton::Inset);
2780 if (!ARDOUR::Profile->get_trx()) {
2781 mode_box->pack_start (edit_mode_selector, false, false);
2783 mode_box->pack_start (*mouse_mode_box, false, false);
2785 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2786 _mouse_mode_tearoff->set_name ("MouseModeBase");
2787 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2789 if (Profile->get_sae()) {
2790 _mouse_mode_tearoff->set_can_be_torn_off (false);
2793 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2794 &_mouse_mode_tearoff->tearoff_window()));
2795 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2796 &_mouse_mode_tearoff->tearoff_window(), 1));
2797 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2798 &_mouse_mode_tearoff->tearoff_window()));
2799 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2800 &_mouse_mode_tearoff->tearoff_window(), 1));
2804 _zoom_box.set_spacing (2);
2805 _zoom_box.set_border_width (2);
2809 zoom_in_button.set_name ("zoom button");
2810 // zoom_in_button.add_elements ( ArdourButton::Inset );
2811 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2812 zoom_in_button.set_image(::get_icon ("zoom_in"));
2813 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2814 zoom_in_button.set_related_action (act);
2816 zoom_out_button.set_name ("zoom button");
2817 // zoom_out_button.add_elements ( ArdourButton::Inset );
2818 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2819 zoom_out_button.set_image(::get_icon ("zoom_out"));
2820 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2821 zoom_out_button.set_related_action (act);
2823 zoom_out_full_button.set_name ("zoom button");
2824 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2825 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2826 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2827 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2828 zoom_out_full_button.set_related_action (act);
2830 zoom_focus_selector.set_name ("zoom button");
2831 zoom_focus_selector.set_size_request (80, -1);
2832 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2834 if (!ARDOUR::Profile->get_trx()) {
2835 _zoom_box.pack_start (zoom_out_button, false, false);
2836 _zoom_box.pack_start (zoom_in_button, false, false);
2837 _zoom_box.pack_start (zoom_out_full_button, false, false);
2838 _zoom_box.pack_start (zoom_focus_selector, false, false);
2840 mode_box->pack_start (zoom_out_button, false, false);
2841 mode_box->pack_start (zoom_in_button, false, false);
2844 /* Track zoom buttons */
2845 visible_tracks_selector.set_name ("zoom button");
2846 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2847 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2849 tav_expand_button.set_name ("zoom button");
2850 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2851 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2852 tav_expand_button.set_size_request (-1, 20);
2853 tav_expand_button.set_image(::get_icon ("tav_exp"));
2854 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2855 tav_expand_button.set_related_action (act);
2857 tav_shrink_button.set_name ("zoom button");
2858 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2859 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2860 tav_shrink_button.set_size_request (-1, 20);
2861 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2862 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2863 tav_shrink_button.set_related_action (act);
2865 if (!ARDOUR::Profile->get_trx()) {
2866 _zoom_box.pack_start (visible_tracks_selector);
2868 _zoom_box.pack_start (tav_shrink_button);
2869 _zoom_box.pack_start (tav_expand_button);
2871 if (!ARDOUR::Profile->get_trx()) {
2872 _zoom_tearoff = manage (new TearOff (_zoom_box));
2874 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2875 &_zoom_tearoff->tearoff_window()));
2876 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2877 &_zoom_tearoff->tearoff_window(), 0));
2878 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2879 &_zoom_tearoff->tearoff_window()));
2880 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2881 &_zoom_tearoff->tearoff_window(), 0));
2884 snap_box.set_spacing (2);
2885 snap_box.set_border_width (2);
2887 snap_type_selector.set_name ("mouse mode button");
2888 snap_type_selector.set_size_request (140, -1);
2889 snap_type_selector.add_elements (ArdourButton::Inset);
2891 snap_mode_selector.set_name ("mouse mode button");
2892 snap_mode_selector.set_size_request (85, -1);
2893 snap_mode_selector.add_elements (ArdourButton::Inset);
2895 edit_point_selector.set_name ("mouse mode button");
2896 edit_point_selector.set_size_request (85, -1);
2897 edit_point_selector.add_elements (ArdourButton::Inset);
2899 snap_box.pack_start (snap_mode_selector, false, false);
2900 snap_box.pack_start (snap_type_selector, false, false);
2901 snap_box.pack_start (edit_point_selector, false, false);
2905 HBox *nudge_box = manage (new HBox);
2906 nudge_box->set_spacing (2);
2907 nudge_box->set_border_width (2);
2909 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2910 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2912 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2913 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2915 nudge_box->pack_start (nudge_backward_button, false, false);
2916 nudge_box->pack_start (nudge_forward_button, false, false);
2917 nudge_box->pack_start (*nudge_clock, false, false);
2920 /* Pack everything in... */
2922 HBox* hbox = manage (new HBox);
2923 hbox->set_spacing(10);
2925 _tools_tearoff = manage (new TearOff (*hbox));
2926 _tools_tearoff->set_name ("MouseModeBase");
2927 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2929 if (Profile->get_sae()) {
2930 _tools_tearoff->set_can_be_torn_off (false);
2933 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2934 &_tools_tearoff->tearoff_window()));
2935 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2936 &_tools_tearoff->tearoff_window(), 0));
2937 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2938 &_tools_tearoff->tearoff_window()));
2939 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2940 &_tools_tearoff->tearoff_window(), 0));
2942 toolbar_hbox.set_spacing (10);
2943 toolbar_hbox.set_border_width (1);
2945 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2946 if (!ARDOUR::Profile->get_trx()) {
2947 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2948 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2951 if (!ARDOUR::Profile->get_trx()) {
2952 hbox->pack_start (snap_box, false, false);
2953 if (!Profile->get_small_screen()) {
2954 hbox->pack_start (*nudge_box, false, false);
2956 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2959 hbox->pack_start (panic_box, false, false);
2963 toolbar_base.set_name ("ToolBarBase");
2964 toolbar_base.add (toolbar_hbox);
2966 _toolbar_viewport.add (toolbar_base);
2967 /* stick to the required height but allow width to vary if there's not enough room */
2968 _toolbar_viewport.set_size_request (1, -1);
2970 toolbar_frame.set_shadow_type (SHADOW_OUT);
2971 toolbar_frame.set_name ("BaseFrame");
2972 toolbar_frame.add (_toolbar_viewport);
2976 Editor::build_edit_point_menu ()
2978 using namespace Menu_Helpers;
2980 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
2981 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
2982 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
2986 Editor::build_edit_mode_menu ()
2988 using namespace Menu_Helpers;
2990 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
2991 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
2992 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
2996 Editor::build_snap_mode_menu ()
2998 using namespace Menu_Helpers;
3000 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3001 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3002 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3006 Editor::build_snap_type_menu ()
3008 using namespace Menu_Helpers;
3010 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3011 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3012 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3013 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3014 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3015 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3016 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3017 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3018 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3019 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3020 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3021 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3022 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3023 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3024 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3025 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3026 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3027 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3028 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3029 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3030 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3031 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3032 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3033 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3034 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3035 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3036 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3037 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3038 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3039 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3043 Editor::setup_tooltips ()
3045 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3046 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3047 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3048 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3049 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3050 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3051 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3052 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3053 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3054 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3055 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3056 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3057 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3058 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3059 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3060 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3061 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3062 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3063 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3064 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3065 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3066 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3067 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3068 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3072 Editor::convert_drop_to_paths (
3073 vector<string>& paths,
3074 const RefPtr<Gdk::DragContext>& /*context*/,
3077 const SelectionData& data,
3081 if (_session == 0) {
3085 vector<string> uris = data.get_uris();
3089 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3090 are actually URI lists. So do it by hand.
3093 if (data.get_target() != "text/plain") {
3097 /* Parse the "uri-list" format that Nautilus provides,
3098 where each pathname is delimited by \r\n.
3100 THERE MAY BE NO NULL TERMINATING CHAR!!!
3103 string txt = data.get_text();
3107 p = (char *) malloc (txt.length() + 1);
3108 txt.copy (p, txt.length(), 0);
3109 p[txt.length()] = '\0';
3115 while (g_ascii_isspace (*p))
3119 while (*q && (*q != '\n') && (*q != '\r')) {
3126 while (q > p && g_ascii_isspace (*q))
3131 uris.push_back (string (p, q - p + 1));
3135 p = strchr (p, '\n');
3147 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3148 if ((*i).substr (0,7) == "file://") {
3149 paths.push_back (Glib::filename_from_uri (*i));
3157 Editor::new_tempo_section ()
3162 Editor::map_transport_state ()
3164 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3166 if (_session && _session->transport_stopped()) {
3167 have_pending_keyboard_selection = false;
3170 update_loop_range_view ();
3176 Editor::begin_reversible_command (string name)
3179 _session->begin_reversible_command (name);
3184 Editor::begin_reversible_command (GQuark q)
3187 _session->begin_reversible_command (q);
3192 Editor::commit_reversible_command ()
3195 _session->commit_reversible_command ();
3200 Editor::history_changed ()
3204 if (undo_action && _session) {
3205 if (_session->undo_depth() == 0) {
3206 label = S_("Command|Undo");
3208 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3210 undo_action->property_label() = label;
3213 if (redo_action && _session) {
3214 if (_session->redo_depth() == 0) {
3217 label = string_compose(_("Redo (%1)"), _session->next_redo());
3219 redo_action->property_label() = label;
3224 Editor::duplicate_range (bool with_dialog)
3228 RegionSelection rs = get_regions_from_selection_and_entered ();
3230 if ( selection->time.length() == 0 && rs.empty()) {
3236 ArdourDialog win (_("Duplicate"));
3237 Label label (_("Number of duplications:"));
3238 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3239 SpinButton spinner (adjustment, 0.0, 1);
3242 win.get_vbox()->set_spacing (12);
3243 win.get_vbox()->pack_start (hbox);
3244 hbox.set_border_width (6);
3245 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3247 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3248 place, visually. so do this by hand.
3251 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3252 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3253 spinner.grab_focus();
3259 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3260 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3261 win.set_default_response (RESPONSE_ACCEPT);
3263 spinner.grab_focus ();
3265 switch (win.run ()) {
3266 case RESPONSE_ACCEPT:
3272 times = adjustment.get_value();
3275 if ((current_mouse_mode() == Editing::MouseRange)) {
3276 if (selection->time.length()) {
3277 duplicate_selection (times);
3279 } else if (get_smart_mode()) {
3280 if (selection->time.length()) {
3281 duplicate_selection (times);
3283 duplicate_some_regions (rs, times);
3285 duplicate_some_regions (rs, times);
3290 Editor::set_edit_mode (EditMode m)
3292 Config->set_edit_mode (m);
3296 Editor::cycle_edit_mode ()
3298 switch (Config->get_edit_mode()) {
3300 if (Profile->get_sae()) {
3301 Config->set_edit_mode (Lock);
3303 Config->set_edit_mode (Splice);
3307 Config->set_edit_mode (Lock);
3310 Config->set_edit_mode (Slide);
3316 Editor::edit_mode_selection_done ( EditMode m )
3318 Config->set_edit_mode ( m );
3322 Editor::snap_type_selection_done (SnapType snaptype)
3324 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3326 ract->set_active ();
3331 Editor::snap_mode_selection_done (SnapMode mode)
3333 RefPtr<RadioAction> ract = snap_mode_action (mode);
3336 ract->set_active (true);
3341 Editor::cycle_edit_point (bool with_marker)
3343 switch (_edit_point) {
3345 set_edit_point_preference (EditAtPlayhead);
3347 case EditAtPlayhead:
3349 set_edit_point_preference (EditAtSelectedMarker);
3351 set_edit_point_preference (EditAtMouse);
3354 case EditAtSelectedMarker:
3355 set_edit_point_preference (EditAtMouse);
3361 Editor::edit_point_selection_done (EditPoint ep)
3363 set_edit_point_preference ( ep );
3367 Editor::build_zoom_focus_menu ()
3369 using namespace Menu_Helpers;
3371 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3372 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3373 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3374 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3375 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3376 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3380 Editor::zoom_focus_selection_done ( ZoomFocus f )
3382 RefPtr<RadioAction> ract = zoom_focus_action (f);
3384 ract->set_active ();
3389 Editor::build_track_count_menu ()
3391 using namespace Menu_Helpers;
3393 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3394 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3395 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3396 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3397 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3398 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3399 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3400 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3401 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3402 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3403 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3404 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3408 Editor::set_visible_track_count (int32_t n)
3410 _visible_track_count = n;
3412 /* if the canvas hasn't really been allocated any size yet, just
3413 record the desired number of visible tracks and return. when canvas
3414 allocation happens, we will get called again and then we can do the
3418 if (_visible_canvas_height <= 1) {
3425 if (_visible_track_count > 0) {
3426 h = _visible_canvas_height / _visible_track_count;
3427 std::ostringstream s;
3428 s << _visible_track_count;
3430 } else if (_visible_track_count == 0) {
3431 h = _visible_canvas_height / track_views.size();
3434 /* negative value means that the visible track count has
3435 been overridden by explicit track height changes.
3437 visible_tracks_selector.set_text (X_("*"));
3441 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3442 (*i)->set_height (h);
3445 if (str != visible_tracks_selector.get_text()) {
3446 visible_tracks_selector.set_text (str);
3451 Editor::override_visible_track_count ()
3453 _visible_track_count = -_visible_track_count;
3457 Editor::edit_controls_button_release (GdkEventButton* ev)
3459 if (Keyboard::is_context_menu_event (ev)) {
3460 ARDOUR_UI::instance()->add_route (this);
3461 } else if (ev->button == 1) {
3462 selection->clear_tracks ();
3469 Editor::mouse_select_button_release (GdkEventButton* ev)
3471 /* this handles just right-clicks */
3473 if (ev->button != 3) {
3481 Editor::set_zoom_focus (ZoomFocus f)
3483 string str = zoom_focus_strings[(int)f];
3485 if (str != zoom_focus_selector.get_text()) {
3486 zoom_focus_selector.set_text (str);
3489 if (zoom_focus != f) {
3496 Editor::cycle_zoom_focus ()
3498 switch (zoom_focus) {
3500 set_zoom_focus (ZoomFocusRight);
3502 case ZoomFocusRight:
3503 set_zoom_focus (ZoomFocusCenter);
3505 case ZoomFocusCenter:
3506 set_zoom_focus (ZoomFocusPlayhead);
3508 case ZoomFocusPlayhead:
3509 set_zoom_focus (ZoomFocusMouse);
3511 case ZoomFocusMouse:
3512 set_zoom_focus (ZoomFocusEdit);
3515 set_zoom_focus (ZoomFocusLeft);
3521 Editor::ensure_float (Window& win)
3523 win.set_transient_for (*this);
3527 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3529 /* recover or initialize pane positions. do this here rather than earlier because
3530 we don't want the positions to change the child allocations, which they seem to do.
3536 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3545 XMLNode* geometry = find_named_node (*node, "geometry");
3547 if (which == static_cast<Paned*> (&edit_pane)) {
3549 if (done & Horizontal) {
3553 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3554 _notebook_shrunk = string_is_affirmative (prop->value ());
3557 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3558 /* initial allocation is 90% to canvas, 10% to notebook */
3559 pos = (int) floor (alloc.get_width() * 0.90f);
3560 snprintf (buf, sizeof(buf), "%d", pos);
3562 pos = atoi (prop->value());
3565 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3566 edit_pane.set_position (pos);
3569 done = (Pane) (done | Horizontal);
3571 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3573 if (done & Vertical) {
3577 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3578 /* initial allocation is 90% to canvas, 10% to summary */
3579 pos = (int) floor (alloc.get_height() * 0.90f);
3580 snprintf (buf, sizeof(buf), "%d", pos);
3583 pos = atoi (prop->value());
3586 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3587 editor_summary_pane.set_position (pos);
3590 done = (Pane) (done | Vertical);
3595 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3597 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3598 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3599 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3600 top_hbox.remove (toolbar_frame);
3605 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3607 if (toolbar_frame.get_parent() == 0) {
3608 top_hbox.pack_end (toolbar_frame);
3613 Editor::set_show_measures (bool yn)
3615 if (_show_measures != yn) {
3618 if ((_show_measures = yn) == true) {
3620 tempo_lines->show();
3623 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3624 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3626 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3627 draw_measures (begin, end);
3635 Editor::toggle_follow_playhead ()
3637 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3639 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3640 set_follow_playhead (tact->get_active());
3644 /** @param yn true to follow playhead, otherwise false.
3645 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3648 Editor::set_follow_playhead (bool yn, bool catch_up)
3650 if (_follow_playhead != yn) {
3651 if ((_follow_playhead = yn) == true && catch_up) {
3653 reset_x_origin_to_follow_playhead ();
3660 Editor::toggle_stationary_playhead ()
3662 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3664 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3665 set_stationary_playhead (tact->get_active());
3670 Editor::set_stationary_playhead (bool yn)
3672 if (_stationary_playhead != yn) {
3673 if ((_stationary_playhead = yn) == true) {
3675 // FIXME need a 3.0 equivalent of this 2.X call
3676 // update_current_screen ();
3683 Editor::playlist_selector () const
3685 return *_playlist_selector;
3689 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3693 switch (_snap_type) {
3698 case SnapToBeatDiv128:
3701 case SnapToBeatDiv64:
3704 case SnapToBeatDiv32:
3707 case SnapToBeatDiv28:
3710 case SnapToBeatDiv24:
3713 case SnapToBeatDiv20:
3716 case SnapToBeatDiv16:
3719 case SnapToBeatDiv14:
3722 case SnapToBeatDiv12:
3725 case SnapToBeatDiv10:
3728 case SnapToBeatDiv8:
3731 case SnapToBeatDiv7:
3734 case SnapToBeatDiv6:
3737 case SnapToBeatDiv5:
3740 case SnapToBeatDiv4:
3743 case SnapToBeatDiv3:
3746 case SnapToBeatDiv2:
3752 return _session->tempo_map().meter_at (position).divisions_per_bar();
3757 case SnapToTimecodeFrame:
3758 case SnapToTimecodeSeconds:
3759 case SnapToTimecodeMinutes:
3762 case SnapToRegionStart:
3763 case SnapToRegionEnd:
3764 case SnapToRegionSync:
3765 case SnapToRegionBoundary:
3775 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3779 ret = nudge_clock->current_duration (pos);
3780 next = ret + 1; /* XXXX fix me */
3786 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3788 ArdourDialog dialog (_("Playlist Deletion"));
3789 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3790 "If it is kept, its audio files will not be cleaned.\n"
3791 "If it is deleted, audio files used by it alone will be cleaned."),
3794 dialog.set_position (WIN_POS_CENTER);
3795 dialog.get_vbox()->pack_start (label);
3799 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3800 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3801 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3803 switch (dialog.run ()) {
3804 case RESPONSE_ACCEPT:
3805 /* delete the playlist */
3809 case RESPONSE_REJECT:
3810 /* keep the playlist */
3822 Editor::audio_region_selection_covers (framepos_t where)
3824 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3825 if ((*a)->region()->covers (where)) {
3834 Editor::prepare_for_cleanup ()
3836 cut_buffer->clear_regions ();
3837 cut_buffer->clear_playlists ();
3839 selection->clear_regions ();
3840 selection->clear_playlists ();
3842 _regions->suspend_redisplay ();
3846 Editor::finish_cleanup ()
3848 _regions->resume_redisplay ();
3852 Editor::transport_loop_location()
3855 return _session->locations()->auto_loop_location();
3862 Editor::transport_punch_location()
3865 return _session->locations()->auto_punch_location();
3872 Editor::control_layout_scroll (GdkEventScroll* ev)
3874 if (Keyboard::some_magic_widget_has_focus()) {
3878 switch (ev->direction) {
3880 scroll_tracks_up_line ();
3884 case GDK_SCROLL_DOWN:
3885 scroll_tracks_down_line ();
3889 /* no left/right handling yet */
3897 Editor::session_state_saved (string)
3900 _snapshots->redisplay ();
3904 Editor::update_tearoff_visibility()
3906 bool visible = Config->get_keep_tearoffs();
3907 _mouse_mode_tearoff->set_visible (visible);
3908 _tools_tearoff->set_visible (visible);
3909 if (_zoom_tearoff) {
3910 _zoom_tearoff->set_visible (visible);
3915 Editor::maximise_editing_space ()
3927 Editor::restore_editing_space ()
3939 * Make new playlists for a given track and also any others that belong
3940 * to the same active route group with the `select' property.
3945 Editor::new_playlists (TimeAxisView* v)
3947 begin_reversible_command (_("new playlists"));
3948 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3949 _session->playlists->get (playlists);
3950 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3951 commit_reversible_command ();
3955 * Use a copy of the current playlist for a given track and also any others that belong
3956 * to the same active route group with the `select' property.
3961 Editor::copy_playlists (TimeAxisView* v)
3963 begin_reversible_command (_("copy playlists"));
3964 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3965 _session->playlists->get (playlists);
3966 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3967 commit_reversible_command ();
3970 /** Clear the current playlist for a given track and also any others that belong
3971 * to the same active route group with the `select' property.
3976 Editor::clear_playlists (TimeAxisView* v)
3978 begin_reversible_command (_("clear playlists"));
3979 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3980 _session->playlists->get (playlists);
3981 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
3982 commit_reversible_command ();
3986 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3988 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3992 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3994 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3998 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4000 atv.clear_playlist ();
4004 Editor::on_key_press_event (GdkEventKey* ev)
4006 return key_press_focus_accelerator_handler (*this, ev);
4010 Editor::on_key_release_event (GdkEventKey* ev)
4012 return Gtk::Window::on_key_release_event (ev);
4013 // return key_press_focus_accelerator_handler (*this, ev);
4016 /** Queue up a change to the viewport x origin.
4017 * @param frame New x origin.
4020 Editor::reset_x_origin (framepos_t frame)
4022 pending_visual_change.add (VisualChange::TimeOrigin);
4023 pending_visual_change.time_origin = frame;
4024 ensure_visual_change_idle_handler ();
4028 Editor::reset_y_origin (double y)
4030 pending_visual_change.add (VisualChange::YOrigin);
4031 pending_visual_change.y_origin = y;
4032 ensure_visual_change_idle_handler ();
4036 Editor::reset_zoom (framecnt_t spp)
4038 clamp_samples_per_pixel (spp);
4040 if (spp == samples_per_pixel) {
4044 pending_visual_change.add (VisualChange::ZoomLevel);
4045 pending_visual_change.samples_per_pixel = spp;
4046 ensure_visual_change_idle_handler ();
4050 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4052 reset_x_origin (frame);
4055 if (!no_save_visual) {
4056 undo_visual_stack.push_back (current_visual_state(false));
4060 Editor::VisualState::VisualState (bool with_tracks)
4061 : gui_state (with_tracks ? new GUIObjectState : 0)
4065 Editor::VisualState::~VisualState ()
4070 Editor::VisualState*
4071 Editor::current_visual_state (bool with_tracks)
4073 VisualState* vs = new VisualState (with_tracks);
4074 vs->y_position = vertical_adjustment.get_value();
4075 vs->samples_per_pixel = samples_per_pixel;
4076 vs->leftmost_frame = leftmost_frame;
4077 vs->zoom_focus = zoom_focus;
4080 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4087 Editor::undo_visual_state ()
4089 if (undo_visual_stack.empty()) {
4093 VisualState* vs = undo_visual_stack.back();
4094 undo_visual_stack.pop_back();
4097 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4099 use_visual_state (*vs);
4103 Editor::redo_visual_state ()
4105 if (redo_visual_stack.empty()) {
4109 VisualState* vs = redo_visual_stack.back();
4110 redo_visual_stack.pop_back();
4112 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4114 use_visual_state (*vs);
4118 Editor::swap_visual_state ()
4120 if (undo_visual_stack.empty()) {
4121 redo_visual_state ();
4123 undo_visual_state ();
4128 Editor::use_visual_state (VisualState& vs)
4130 PBD::Unwinder<bool> nsv (no_save_visual, true);
4132 _routes->suspend_redisplay ();
4134 vertical_adjustment.set_value (vs.y_position);
4136 set_zoom_focus (vs.zoom_focus);
4137 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4140 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4142 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4143 (*i)->reset_visual_state ();
4147 _routes->update_visibility ();
4148 _routes->resume_redisplay ();
4151 /** This is the core function that controls the zoom level of the canvas. It is called
4152 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4153 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4156 Editor::set_samples_per_pixel (framecnt_t spp)
4158 clamp_samples_per_pixel (spp);
4159 samples_per_pixel = spp;
4162 tempo_lines->tempo_map_changed();
4165 /* convert fpu to frame count */
4167 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4169 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4170 zoom_range_clock->set (frames);
4173 bool const showing_time_selection = selection->time.length() > 0;
4175 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4176 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4177 (*i)->reshow_selection (selection->time);
4181 ZoomChanged (); /* EMIT_SIGNAL */
4183 ArdourCanvas::GtkCanvasViewport* c;
4185 c = get_track_canvas();
4187 c->canvas()->zoomed ();
4190 if (playhead_cursor) {
4191 playhead_cursor->set_position (playhead_cursor->current_frame ());
4194 refresh_location_display();
4195 _summary->set_overlays_dirty ();
4197 update_marker_labels ();
4203 Editor::queue_visual_videotimeline_update ()
4206 * pending_visual_change.add (VisualChange::VideoTimeline);
4207 * or maybe even more specific: which videotimeline-image
4208 * currently it calls update_video_timeline() to update
4209 * _all outdated_ images on the video-timeline.
4210 * see 'exposeimg()' in video_image_frame.cc
4212 ensure_visual_change_idle_handler ();
4216 Editor::ensure_visual_change_idle_handler ()
4218 if (pending_visual_change.idle_handler_id < 0) {
4219 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4220 pending_visual_change.being_handled = false;
4225 Editor::_idle_visual_changer (void* arg)
4227 return static_cast<Editor*>(arg)->idle_visual_changer ();
4231 Editor::idle_visual_changer ()
4233 /* set_horizontal_position() below (and maybe other calls) call
4234 gtk_main_iteration(), so it's possible that a signal will be handled
4235 half-way through this method. If this signal wants an
4236 idle_visual_changer we must schedule another one after this one, so
4237 mark the idle_handler_id as -1 here to allow that. Also make a note
4238 that we are doing the visual change, so that changes in response to
4239 super-rapid-screen-update can be dropped if we are still processing
4243 pending_visual_change.idle_handler_id = -1;
4244 pending_visual_change.being_handled = true;
4246 VisualChange vc = pending_visual_change;
4248 pending_visual_change.pending = (VisualChange::Type) 0;
4250 visual_changer (vc);
4252 pending_visual_change.being_handled = false;
4254 return 0; /* this is always a one-shot call */
4258 Editor::visual_changer (const VisualChange& vc)
4260 double const last_time_origin = horizontal_position ();
4262 if (vc.pending & VisualChange::ZoomLevel) {
4263 set_samples_per_pixel (vc.samples_per_pixel);
4265 compute_fixed_ruler_scale ();
4267 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4268 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4270 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4271 current_bbt_points_begin, current_bbt_points_end);
4272 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4273 current_bbt_points_begin, current_bbt_points_end);
4274 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4276 update_video_timeline();
4279 if (vc.pending & VisualChange::TimeOrigin) {
4280 set_horizontal_position (vc.time_origin / samples_per_pixel);
4283 if (vc.pending & VisualChange::YOrigin) {
4284 vertical_adjustment.set_value (vc.y_origin);
4287 if (last_time_origin == horizontal_position ()) {
4288 /* changed signal not emitted */
4289 update_fixed_rulers ();
4290 redisplay_tempo (true);
4293 if (!(vc.pending & VisualChange::ZoomLevel)) {
4294 update_video_timeline();
4297 _summary->set_overlays_dirty ();
4300 struct EditorOrderTimeAxisSorter {
4301 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4302 return a->order () < b->order ();
4307 Editor::sort_track_selection (TrackViewList& sel)
4309 EditorOrderTimeAxisSorter cmp;
4314 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4317 framepos_t where = 0;
4318 EditPoint ep = _edit_point;
4320 if (from_context_menu && (ep == EditAtMouse)) {
4321 return canvas_event_sample (&context_click_event, 0, 0);
4324 if (entered_marker) {
4325 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4326 return entered_marker->position();
4329 if (ignore_playhead && ep == EditAtPlayhead) {
4330 ep = EditAtSelectedMarker;
4334 case EditAtPlayhead:
4335 where = _session->audible_frame();
4336 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4339 case EditAtSelectedMarker:
4340 if (!selection->markers.empty()) {
4342 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4345 where = loc->start();
4349 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4357 if (!mouse_frame (where, ignored)) {
4358 /* XXX not right but what can we do ? */
4362 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4370 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4372 if (!_session) return;
4374 begin_reversible_command (cmd);
4378 if ((tll = transport_loop_location()) == 0) {
4379 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4380 XMLNode &before = _session->locations()->get_state();
4381 _session->locations()->add (loc, true);
4382 _session->set_auto_loop_location (loc);
4383 XMLNode &after = _session->locations()->get_state();
4384 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4386 XMLNode &before = tll->get_state();
4387 tll->set_hidden (false, this);
4388 tll->set (start, end);
4389 XMLNode &after = tll->get_state();
4390 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4393 commit_reversible_command ();
4397 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4399 if (!_session) return;
4401 begin_reversible_command (cmd);
4405 if ((tpl = transport_punch_location()) == 0) {
4406 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4407 XMLNode &before = _session->locations()->get_state();
4408 _session->locations()->add (loc, true);
4409 _session->set_auto_punch_location (loc);
4410 XMLNode &after = _session->locations()->get_state();
4411 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4414 XMLNode &before = tpl->get_state();
4415 tpl->set_hidden (false, this);
4416 tpl->set (start, end);
4417 XMLNode &after = tpl->get_state();
4418 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4421 commit_reversible_command ();
4424 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4425 * @param rs List to which found regions are added.
4426 * @param where Time to look at.
4427 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4430 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4432 const TrackViewList* tracks;
4435 tracks = &track_views;
4440 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4442 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4445 boost::shared_ptr<Track> tr;
4446 boost::shared_ptr<Playlist> pl;
4448 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4450 boost::shared_ptr<RegionList> regions = pl->regions_at (
4451 (framepos_t) floor ( (double) where * tr->speed()));
4453 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4454 RegionView* rv = rtv->view()->find_view (*i);
4465 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4467 const TrackViewList* tracks;
4470 tracks = &track_views;
4475 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4476 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4478 boost::shared_ptr<Track> tr;
4479 boost::shared_ptr<Playlist> pl;
4481 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4483 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4484 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4486 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4488 RegionView* rv = rtv->view()->find_view (*i);
4499 /** Get regions using the following method:
4501 * Make a region list using the selected regions, unless
4502 * the edit point is `mouse' and the mouse is over an unselected
4503 * region. In this case, use just that region.
4505 * If the edit point is not 'mouse', and there are no regions selected,
4506 * search the list of selected tracks and return regions that are under
4507 * the edit point on these tracks. If there are no selected tracks and
4508 * 'No Selection = All Tracks' is active, search all tracks,
4510 * The rationale here is that the mouse edit point is special in that
4511 * its position describes both a time and a track; the other edit
4512 * modes only describe a time. Hence if the edit point is `mouse' we
4513 * ignore selected tracks, as we assume the user means something by
4514 * pointing at a particular track. Also in this case we take note of
4515 * the region directly under the edit point, as there is always just one
4516 * (rather than possibly several with non-mouse edit points).
4520 Editor::get_regions_from_selection_and_edit_point ()
4522 RegionSelection regions;
4524 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4525 regions.add (entered_regionview);
4527 regions = selection->regions;
4531 if (regions.empty() && _edit_point != EditAtMouse) {
4532 TrackViewList tracks = selection->tracks;
4534 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4535 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4536 * is enabled, so consider all tracks
4538 tracks = track_views;
4541 if (!tracks.empty()) {
4542 /* no region selected or entered, but some selected tracks:
4543 * act on all regions on the selected tracks at the edit point
4545 framepos_t const where = get_preferred_edit_position ();
4546 get_regions_at(regions, where, tracks);
4552 /** Start with regions that are selected, or the entered regionview if none are selected.
4553 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4554 * of the regions that we started with.
4558 Editor::get_regions_from_selection_and_entered ()
4560 RegionSelection regions = selection->regions;
4562 if (regions.empty() && entered_regionview) {
4563 regions.add (entered_regionview);
4570 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4572 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4574 RouteTimeAxisView* tatv;
4576 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4578 boost::shared_ptr<Playlist> pl;
4579 vector<boost::shared_ptr<Region> > results;
4581 boost::shared_ptr<Track> tr;
4583 if ((tr = tatv->track()) == 0) {
4588 if ((pl = (tr->playlist())) != 0) {
4589 if (src_comparison) {
4590 pl->get_source_equivalent_regions (region, results);
4592 pl->get_region_list_equivalent_regions (region, results);
4596 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4597 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4598 regions.push_back (marv);
4607 Editor::show_rhythm_ferret ()
4609 if (rhythm_ferret == 0) {
4610 rhythm_ferret = new RhythmFerret(*this);
4613 rhythm_ferret->set_session (_session);
4614 rhythm_ferret->show ();
4615 rhythm_ferret->present ();
4619 Editor::first_idle ()
4621 MessageDialog* dialog = 0;
4623 if (track_views.size() > 1) {
4624 dialog = new MessageDialog (
4626 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4630 ARDOUR_UI::instance()->flush_pending ();
4633 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4637 // first idle adds route children (automation tracks), so we need to redisplay here
4638 _routes->redisplay ();
4645 Editor::_idle_resize (gpointer arg)
4647 return ((Editor*)arg)->idle_resize ();
4651 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4653 if (resize_idle_id < 0) {
4654 resize_idle_id = g_idle_add (_idle_resize, this);
4655 _pending_resize_amount = 0;
4658 /* make a note of the smallest resulting height, so that we can clamp the
4659 lower limit at TimeAxisView::hSmall */
4661 int32_t min_resulting = INT32_MAX;
4663 _pending_resize_amount += h;
4664 _pending_resize_view = view;
4666 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4668 if (selection->tracks.contains (_pending_resize_view)) {
4669 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4670 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4674 if (min_resulting < 0) {
4679 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4680 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4684 /** Handle pending resizing of tracks */
4686 Editor::idle_resize ()
4688 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4690 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4691 selection->tracks.contains (_pending_resize_view)) {
4693 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4694 if (*i != _pending_resize_view) {
4695 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4700 _pending_resize_amount = 0;
4701 _group_tabs->set_dirty ();
4702 resize_idle_id = -1;
4710 ENSURE_GUI_THREAD (*this, &Editor::located);
4713 playhead_cursor->set_position (_session->audible_frame ());
4714 if (_follow_playhead && !_pending_initial_locate) {
4715 reset_x_origin_to_follow_playhead ();
4719 _pending_locate_request = false;
4720 _pending_initial_locate = false;
4724 Editor::region_view_added (RegionView *)
4726 _summary->set_dirty ();
4730 Editor::region_view_removed ()
4732 _summary->set_dirty ();
4736 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4738 TrackViewList::const_iterator j = track_views.begin ();
4739 while (j != track_views.end()) {
4740 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4741 if (rtv && rtv->route() == r) {
4752 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4756 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4757 TimeAxisView* tv = axis_view_from_route (*i);
4767 Editor::add_routes (RouteList& routes)
4769 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4771 RouteTimeAxisView *rtv;
4772 list<RouteTimeAxisView*> new_views;
4774 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4775 boost::shared_ptr<Route> route = (*x);
4777 if (route->is_auditioner() || route->is_monitor()) {
4781 DataType dt = route->input()->default_type();
4783 if (dt == ARDOUR::DataType::AUDIO) {
4784 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4785 rtv->set_route (route);
4786 } else if (dt == ARDOUR::DataType::MIDI) {
4787 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4788 rtv->set_route (route);
4790 throw unknown_type();
4793 new_views.push_back (rtv);
4794 track_views.push_back (rtv);
4796 rtv->effective_gain_display ();
4798 if (internal_editing()) {
4799 rtv->enter_internal_edit_mode ();
4801 rtv->leave_internal_edit_mode ();
4804 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4805 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4808 if (new_views.size() > 0) {
4809 _routes->routes_added (new_views);
4810 _summary->routes_added (new_views);
4813 if (show_editor_mixer_when_tracks_arrive) {
4814 show_editor_mixer (true);
4817 editor_list_button.set_sensitive (true);
4821 Editor::timeaxisview_deleted (TimeAxisView *tv)
4823 if (_session && _session->deletion_in_progress()) {
4824 /* the situation is under control */
4828 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4830 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4832 _routes->route_removed (tv);
4834 if (tv == entered_track) {
4838 TimeAxisView::Children c = tv->get_child_list ();
4839 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4840 if (entered_track == i->get()) {
4845 /* remove it from the list of track views */
4847 TrackViewList::iterator i;
4849 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4850 i = track_views.erase (i);
4853 /* update whatever the current mixer strip is displaying, if revelant */
4855 boost::shared_ptr<Route> route;
4858 route = rtav->route ();
4861 if (current_mixer_strip && current_mixer_strip->route() == route) {
4863 TimeAxisView* next_tv;
4865 if (track_views.empty()) {
4867 } else if (i == track_views.end()) {
4868 next_tv = track_views.front();
4875 set_selected_mixer_strip (*next_tv);
4877 /* make the editor mixer strip go away setting the
4878 * button to inactive (which also unticks the menu option)
4881 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4887 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4889 if (apply_to_selection) {
4890 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4892 TrackSelection::iterator j = i;
4895 hide_track_in_display (*i, false);
4900 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4902 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4903 // this will hide the mixer strip
4904 set_selected_mixer_strip (*tv);
4907 _routes->hide_track_in_display (*tv);
4912 Editor::sync_track_view_list_and_routes ()
4914 track_views = TrackViewList (_routes->views ());
4916 _summary->set_dirty ();
4917 _group_tabs->set_dirty ();
4919 return false; // do not call again (until needed)
4923 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4925 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4930 /** Find a RouteTimeAxisView by the ID of its route */
4932 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4934 RouteTimeAxisView* v;
4936 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4937 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4938 if(v->route()->id() == id) {
4948 Editor::fit_route_group (RouteGroup *g)
4950 TrackViewList ts = axis_views_from_routes (g->route_list ());
4955 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4957 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4960 _session->cancel_audition ();
4964 if (_session->is_auditioning()) {
4965 _session->cancel_audition ();
4966 if (r == last_audition_region) {
4971 _session->audition_region (r);
4972 last_audition_region = r;
4977 Editor::hide_a_region (boost::shared_ptr<Region> r)
4979 r->set_hidden (true);
4983 Editor::show_a_region (boost::shared_ptr<Region> r)
4985 r->set_hidden (false);
4989 Editor::audition_region_from_region_list ()
4991 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4995 Editor::hide_region_from_region_list ()
4997 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5001 Editor::show_region_in_region_list ()
5003 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5007 Editor::step_edit_status_change (bool yn)
5010 start_step_editing ();
5012 stop_step_editing ();
5017 Editor::start_step_editing ()
5019 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5023 Editor::stop_step_editing ()
5025 step_edit_connection.disconnect ();
5029 Editor::check_step_edit ()
5031 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5032 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5034 mtv->check_step_edit ();
5038 return true; // do it again, till we stop
5042 Editor::scroll_press (Direction dir)
5044 ++_scroll_callbacks;
5046 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5047 /* delay the first auto-repeat */
5053 scroll_backward (1);
5061 scroll_tracks_up_line ();
5065 scroll_tracks_down_line ();
5069 /* do hacky auto-repeat */
5070 if (!_scroll_connection.connected ()) {
5072 _scroll_connection = Glib::signal_timeout().connect (
5073 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5076 _scroll_callbacks = 0;
5083 Editor::scroll_release ()
5085 _scroll_connection.disconnect ();
5088 /** Queue a change for the Editor viewport x origin to follow the playhead */
5090 Editor::reset_x_origin_to_follow_playhead ()
5092 framepos_t const frame = playhead_cursor->current_frame ();
5094 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5096 if (_session->transport_speed() < 0) {
5098 if (frame > (current_page_samples() / 2)) {
5099 center_screen (frame-(current_page_samples()/2));
5101 center_screen (current_page_samples()/2);
5108 if (frame < leftmost_frame) {
5110 if (_session->transport_rolling()) {
5111 /* rolling; end up with the playhead at the right of the page */
5112 l = frame - current_page_samples ();
5114 /* not rolling: end up with the playhead 1/4 of the way along the page */
5115 l = frame - current_page_samples() / 4;
5119 if (_session->transport_rolling()) {
5120 /* rolling: end up with the playhead on the left of the page */
5123 /* not rolling: end up with the playhead 3/4 of the way along the page */
5124 l = frame - 3 * current_page_samples() / 4;
5132 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5138 Editor::super_rapid_screen_update ()
5140 if (!_session || !_session->engine().running()) {
5144 /* METERING / MIXER STRIPS */
5146 /* update track meters, if required */
5147 if (is_mapped() && meters_running) {
5148 RouteTimeAxisView* rtv;
5149 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5150 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5151 rtv->fast_update ();
5156 /* and any current mixer strip */
5157 if (current_mixer_strip) {
5158 current_mixer_strip->fast_update ();
5161 /* PLAYHEAD AND VIEWPORT */
5163 framepos_t const frame = _session->audible_frame();
5165 /* There are a few reasons why we might not update the playhead / viewport stuff:
5167 * 1. we don't update things when there's a pending locate request, otherwise
5168 * when the editor requests a locate there is a chance that this method
5169 * will move the playhead before the locate request is processed, causing
5171 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5172 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5175 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5177 last_update_frame = frame;
5179 if (!_dragging_playhead) {
5180 playhead_cursor->set_position (frame);
5183 if (!_stationary_playhead) {
5185 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5186 /* We only do this if we aren't already
5187 handling a visual change (ie if
5188 pending_visual_change.being_handled is
5189 false) so that these requests don't stack
5190 up there are too many of them to handle in
5193 reset_x_origin_to_follow_playhead ();
5198 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5202 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5203 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5204 if (target <= 0.0) {
5207 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5208 target = (target * 0.15) + (current * 0.85);
5214 set_horizontal_position (current);
5223 Editor::session_going_away ()
5225 _have_idled = false;
5227 _session_connections.drop_connections ();
5229 super_rapid_screen_update_connection.disconnect ();
5231 selection->clear ();
5232 cut_buffer->clear ();
5234 clicked_regionview = 0;
5235 clicked_axisview = 0;
5236 clicked_routeview = 0;
5237 entered_regionview = 0;
5239 last_update_frame = 0;
5242 playhead_cursor->hide ();
5244 /* rip everything out of the list displays */
5248 _route_groups->clear ();
5250 /* do this first so that deleting a track doesn't reset cms to null
5251 and thus cause a leak.
5254 if (current_mixer_strip) {
5255 if (current_mixer_strip->get_parent() != 0) {
5256 global_hpacker.remove (*current_mixer_strip);
5258 delete current_mixer_strip;
5259 current_mixer_strip = 0;
5262 /* delete all trackviews */
5264 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5267 track_views.clear ();
5269 zoom_range_clock->set_session (0);
5270 nudge_clock->set_session (0);
5272 editor_list_button.set_active(false);
5273 editor_list_button.set_sensitive(false);
5275 /* clear tempo/meter rulers */
5276 remove_metric_marks ();
5278 clear_marker_display ();
5280 stop_step_editing ();
5282 /* get rid of any existing editor mixer strip */
5284 WindowTitle title(Glib::get_application_name());
5285 title += _("Editor");
5287 set_title (title.get_string());
5289 SessionHandlePtr::session_going_away ();
5294 Editor::show_editor_list (bool yn)
5297 _the_notebook.show ();
5299 _the_notebook.hide ();
5304 Editor::change_region_layering_order (bool from_context_menu)
5306 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5308 if (!clicked_routeview) {
5309 if (layering_order_editor) {
5310 layering_order_editor->hide ();
5315 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5321 boost::shared_ptr<Playlist> pl = track->playlist();
5327 if (layering_order_editor == 0) {
5328 layering_order_editor = new RegionLayeringOrderEditor (*this);
5331 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5332 layering_order_editor->maybe_present ();
5336 Editor::update_region_layering_order_editor ()
5338 if (layering_order_editor && layering_order_editor->is_visible ()) {
5339 change_region_layering_order (true);
5344 Editor::setup_fade_images ()
5346 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5347 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5348 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5349 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5350 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5352 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5353 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5354 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5355 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5356 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5358 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5359 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5360 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5361 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5362 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5364 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5365 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5366 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5367 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5368 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5372 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5374 Editor::action_menu_item (std::string const & name)
5376 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5379 return *manage (a->create_menu_item ());
5383 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5385 EventBox* b = manage (new EventBox);
5386 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5387 Label* l = manage (new Label (name));
5391 _the_notebook.append_page (widget, *b);
5395 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5397 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5398 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5401 if (ev->type == GDK_2BUTTON_PRESS) {
5403 /* double-click on a notebook tab shrinks or expands the notebook */
5405 if (_notebook_shrunk) {
5406 if (pre_notebook_shrink_pane_width) {
5407 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5409 _notebook_shrunk = false;
5411 pre_notebook_shrink_pane_width = edit_pane.get_position();
5413 /* this expands the LHS of the edit pane to cover the notebook
5414 PAGE but leaves the tabs visible.
5416 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5417 _notebook_shrunk = true;
5425 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5427 using namespace Menu_Helpers;
5429 MenuList& items = _control_point_context_menu.items ();
5432 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5433 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5434 if (!can_remove_control_point (item)) {
5435 items.back().set_sensitive (false);
5438 _control_point_context_menu.popup (event->button.button, event->button.time);
5442 Editor::zoom_vertical_modifier_released()
5444 _stepping_axis_view = 0;