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::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
499 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
500 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
502 _cursors = new MouseCursors;
504 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
506 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
507 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
508 pad_line_1->set_outline_color (0xFF0000FF);
514 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
515 time_canvas_vbox.set_size_request (-1, -1);
517 ruler_label_event_box.add (ruler_label_vbox);
518 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
519 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
521 time_bars_event_box.add (time_bars_vbox);
522 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
523 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
525 time_canvas_event_box.add (time_canvas_vbox);
526 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
528 edit_packer.set_col_spacings (0);
529 edit_packer.set_row_spacings (0);
530 edit_packer.set_homogeneous (false);
531 edit_packer.set_border_width (0);
532 edit_packer.set_name ("EditorWindow");
534 /* labels for the rulers */
535 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
536 /* labels for the marker "tracks" (time bars) */
537 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
539 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
541 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
543 edit_packer.attach (*_track_canvas_viewport, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
545 bottom_hbox.set_border_width (2);
546 bottom_hbox.set_spacing (3);
548 _route_groups = new EditorRouteGroups (this);
549 _routes = new EditorRoutes (this);
550 _regions = new EditorRegions (this);
551 _snapshots = new EditorSnapshots (this);
552 _locations = new EditorLocations (this);
554 add_notebook_page (_("Regions"), _regions->widget ());
555 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
556 add_notebook_page (_("Snapshots"), _snapshots->widget ());
557 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
558 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
560 _the_notebook.set_show_tabs (true);
561 _the_notebook.set_scrollable (true);
562 _the_notebook.popup_disable ();
563 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
564 _the_notebook.show_all ();
566 _notebook_shrunk = false;
568 editor_summary_pane.pack1(edit_packer);
570 Button* summary_arrows_left_left = manage (new Button);
571 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
572 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
573 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_left_right = manage (new Button);
576 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
577 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
578 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_left = manage (new VBox);
581 summary_arrows_left->pack_start (*summary_arrows_left_left);
582 summary_arrows_left->pack_start (*summary_arrows_left_right);
584 Button* summary_arrows_right_up = manage (new Button);
585 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
586 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
587 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 Button* summary_arrows_right_down = manage (new Button);
590 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
591 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
592 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
594 VBox* summary_arrows_right = manage (new VBox);
595 summary_arrows_right->pack_start (*summary_arrows_right_up);
596 summary_arrows_right->pack_start (*summary_arrows_right_down);
598 Frame* summary_frame = manage (new Frame);
599 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
601 summary_frame->add (*_summary);
602 summary_frame->show ();
604 _summary_hbox.pack_start (*summary_arrows_left, false, false);
605 _summary_hbox.pack_start (*summary_frame, true, true);
606 _summary_hbox.pack_start (*summary_arrows_right, false, false);
608 if (!ARDOUR::Profile->get_trx()) {
609 editor_summary_pane.pack2 (_summary_hbox);
612 edit_pane.pack1 (editor_summary_pane, true, true);
613 if (!ARDOUR::Profile->get_trx()) {
614 edit_pane.pack2 (_the_notebook, false, true);
617 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
619 /* XXX: editor_summary_pane might need similar to the edit_pane */
621 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
623 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
624 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
626 top_hbox.pack_start (toolbar_frame);
628 HBox *hbox = manage (new HBox);
629 hbox->pack_start (edit_pane, true, true);
631 global_vpacker.pack_start (top_hbox, false, false);
632 global_vpacker.pack_start (*hbox, true, true);
634 global_hpacker.pack_start (global_vpacker, true, true);
636 set_name ("EditorWindow");
637 add_accel_group (ActionManager::ui_manager->get_accel_group());
639 status_bar_hpacker.show ();
641 vpacker.pack_end (status_bar_hpacker, false, false);
642 vpacker.pack_end (global_hpacker, true, true);
644 /* register actions now so that set_state() can find them and set toggles/checks etc */
647 /* when we start using our own keybinding system for the editor, this
648 * will be uncommented
654 set_zoom_focus (zoom_focus);
655 set_visible_track_count (_visible_track_count);
656 _snap_type = SnapToBeat;
657 set_snap_to (_snap_type);
658 _snap_mode = SnapOff;
659 set_snap_mode (_snap_mode);
660 set_mouse_mode (MouseObject, true);
661 pre_internal_mouse_mode = MouseObject;
662 pre_internal_snap_type = _snap_type;
663 pre_internal_snap_mode = _snap_mode;
664 internal_snap_type = _snap_type;
665 internal_snap_mode = _snap_mode;
666 set_edit_point_preference (EditAtMouse, true);
668 _playlist_selector = new PlaylistSelector();
669 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
671 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
675 nudge_forward_button.set_name ("nudge button");
676 // nudge_forward_button.add_elements (ArdourButton::Inset);
677 nudge_forward_button.set_image(::get_icon("nudge_right"));
679 nudge_backward_button.set_name ("nudge button");
680 // nudge_backward_button.add_elements (ArdourButton::Inset);
681 nudge_backward_button.set_image(::get_icon("nudge_left"));
683 fade_context_menu.set_name ("ArdourContextMenu");
685 /* icons, titles, WM stuff */
687 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
688 Glib::RefPtr<Gdk::Pixbuf> icon;
690 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
691 window_icons.push_back (icon);
693 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
694 window_icons.push_back (icon);
696 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
697 window_icons.push_back (icon);
699 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
700 window_icons.push_back (icon);
702 if (!window_icons.empty()) {
703 // set_icon_list (window_icons);
704 set_default_icon_list (window_icons);
707 WindowTitle title(Glib::get_application_name());
708 title += _("Editor");
709 set_title (title.get_string());
710 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
713 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
715 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
716 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
718 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
720 /* allow external control surfaces/protocols to do various things */
722 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
723 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
724 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
725 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
726 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
727 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
728 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
729 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
730 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
731 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
732 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
733 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
734 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
735 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
737 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
738 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
739 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
740 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
741 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
743 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
745 /* problematic: has to return a value and thus cannot be x-thread */
747 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
749 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
751 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
753 _ignore_region_action = false;
754 _last_region_menu_was_main = false;
755 _popup_region_menu_item = 0;
757 _show_marker_lines = false;
758 _over_region_trim_target = false;
760 /* Button bindings */
762 button_bindings = new Bindings;
764 XMLNode* node = button_settings();
766 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
767 button_bindings->load (**i);
774 setup_fade_images ();
779 delete button_bindings;
781 delete _route_groups;
782 delete _track_canvas_viewport;
787 Editor::button_settings () const
789 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
790 XMLNode* node = find_named_node (*settings, X_("Buttons"));
793 node = new XMLNode (X_("Buttons"));
800 Editor::add_toplevel_controls (Container& cont)
802 vpacker.pack_start (cont, false, false);
807 Editor::get_smart_mode () const
809 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
813 Editor::catch_vanishing_regionview (RegionView *rv)
815 /* note: the selection will take care of the vanishing
816 audioregionview by itself.
819 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
823 if (clicked_regionview == rv) {
824 clicked_regionview = 0;
827 if (entered_regionview == rv) {
828 set_entered_regionview (0);
831 if (!_all_region_actions_sensitized) {
832 sensitize_all_region_actions (true);
835 _over_region_trim_target = false;
839 Editor::set_entered_regionview (RegionView* rv)
841 if (rv == entered_regionview) {
845 if (entered_regionview) {
846 entered_regionview->exited ();
849 if ((entered_regionview = rv) != 0) {
850 entered_regionview->entered (internal_editing ());
853 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
854 /* This RegionView entry might have changed what region actions
855 are allowed, so sensitize them all in case a key is pressed.
857 sensitize_all_region_actions (true);
862 Editor::set_entered_track (TimeAxisView* tav)
865 entered_track->exited ();
868 if ((entered_track = tav) != 0) {
869 entered_track->entered ();
874 Editor::show_window ()
876 if (!is_visible ()) {
879 /* XXX: this is a bit unfortunate; it would probably
880 be nicer if we could just call show () above rather
881 than needing the show_all ()
884 /* re-hide stuff if necessary */
885 editor_list_button_toggled ();
886 parameter_changed ("show-summary");
887 parameter_changed ("show-group-tabs");
888 parameter_changed ("show-zoom-tools");
890 /* now reset all audio_time_axis heights, because widgets might need
896 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
897 tv = (static_cast<TimeAxisView*>(*i));
901 if (current_mixer_strip) {
902 current_mixer_strip->hide_things ();
903 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
911 Editor::instant_save ()
913 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
918 _session->add_instant_xml(get_state());
920 Config->add_instant_xml(get_state());
925 Editor::zoom_adjustment_changed ()
931 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
932 bool clamped = clamp_samples_per_pixel (fpu);
935 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
942 Editor::control_vertical_zoom_in_all ()
944 tav_zoom_smooth (false, true);
948 Editor::control_vertical_zoom_out_all ()
950 tav_zoom_smooth (true, true);
954 Editor::control_vertical_zoom_in_selected ()
956 tav_zoom_smooth (false, false);
960 Editor::control_vertical_zoom_out_selected ()
962 tav_zoom_smooth (true, false);
966 Editor::control_view (uint32_t view)
968 goto_visual_state (view);
972 Editor::control_unselect ()
974 selection->clear_tracks ();
978 Editor::control_select (uint32_t rid, Selection::Operation op)
980 /* handles the (static) signal from the ControlProtocol class that
981 * requests setting the selected track to a given RID
988 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
994 TimeAxisView* tav = axis_view_from_route (r);
999 selection->add (tav);
1001 case Selection::Toggle:
1002 selection->toggle (tav);
1004 case Selection::Extend:
1006 case Selection::Set:
1007 selection->set (tav);
1011 selection->clear_tracks ();
1016 Editor::control_step_tracks_up ()
1018 scroll_tracks_up_line ();
1022 Editor::control_step_tracks_down ()
1024 scroll_tracks_down_line ();
1028 Editor::control_scroll (float fraction)
1030 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1036 double step = fraction * current_page_samples();
1039 _control_scroll_target is an optional<T>
1041 it acts like a pointer to an framepos_t, with
1042 a operator conversion to boolean to check
1043 that it has a value could possibly use
1044 playhead_cursor->current_frame to store the
1045 value and a boolean in the class to know
1046 when it's out of date
1049 if (!_control_scroll_target) {
1050 _control_scroll_target = _session->transport_frame();
1051 _dragging_playhead = true;
1054 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1055 *_control_scroll_target = 0;
1056 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1057 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1059 *_control_scroll_target += (framepos_t) floor (step);
1062 /* move visuals, we'll catch up with it later */
1064 playhead_cursor->set_position (*_control_scroll_target);
1065 UpdateAllTransportClocks (*_control_scroll_target);
1067 if (*_control_scroll_target > (current_page_samples() / 2)) {
1068 /* try to center PH in window */
1069 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1075 Now we do a timeout to actually bring the session to the right place
1076 according to the playhead. This is to avoid reading disk buffers on every
1077 call to control_scroll, which is driven by ScrollTimeline and therefore
1078 probably by a control surface wheel which can generate lots of events.
1080 /* cancel the existing timeout */
1082 control_scroll_connection.disconnect ();
1084 /* add the next timeout */
1086 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1090 Editor::deferred_control_scroll (framepos_t /*target*/)
1092 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1093 // reset for next stream
1094 _control_scroll_target = boost::none;
1095 _dragging_playhead = false;
1100 Editor::access_action (std::string action_group, std::string action_item)
1106 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1109 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1117 Editor::on_realize ()
1119 Window::on_realize ();
1124 Editor::map_position_change (framepos_t frame)
1126 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1128 if (_session == 0) {
1132 if (_follow_playhead) {
1133 center_screen (frame);
1136 playhead_cursor->set_position (frame);
1140 Editor::center_screen (framepos_t frame)
1142 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1144 /* if we're off the page, then scroll.
1147 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1148 center_screen_internal (frame, page);
1153 Editor::center_screen_internal (framepos_t frame, float page)
1158 frame -= (framepos_t) page;
1163 reset_x_origin (frame);
1168 Editor::update_title ()
1170 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1173 bool dirty = _session->dirty();
1175 string session_name;
1177 if (_session->snap_name() != _session->name()) {
1178 session_name = _session->snap_name();
1180 session_name = _session->name();
1184 session_name = "*" + session_name;
1187 WindowTitle title(session_name);
1188 title += Glib::get_application_name();
1189 set_title (title.get_string());
1191 /* ::session_going_away() will have taken care of it */
1196 Editor::set_session (Session *t)
1198 SessionHandlePtr::set_session (t);
1204 zoom_range_clock->set_session (_session);
1205 _playlist_selector->set_session (_session);
1206 nudge_clock->set_session (_session);
1207 _summary->set_session (_session);
1208 _group_tabs->set_session (_session);
1209 _route_groups->set_session (_session);
1210 _regions->set_session (_session);
1211 _snapshots->set_session (_session);
1212 _routes->set_session (_session);
1213 _locations->set_session (_session);
1215 if (rhythm_ferret) {
1216 rhythm_ferret->set_session (_session);
1219 if (analysis_window) {
1220 analysis_window->set_session (_session);
1224 sfbrowser->set_session (_session);
1227 compute_fixed_ruler_scale ();
1229 /* Make sure we have auto loop and auto punch ranges */
1231 Location* loc = _session->locations()->auto_loop_location();
1233 loc->set_name (_("Loop"));
1236 loc = _session->locations()->auto_punch_location();
1239 loc->set_name (_("Punch"));
1242 refresh_location_display ();
1244 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1245 the selected Marker; this needs the LocationMarker list to be available.
1247 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1248 set_state (*node, Stateful::loading_state_version);
1250 /* catch up with the playhead */
1252 _session->request_locate (playhead_cursor->current_frame ());
1253 _pending_initial_locate = true;
1257 /* These signals can all be emitted by a non-GUI thread. Therefore the
1258 handlers for them must not attempt to directly interact with the GUI,
1259 but use PBD::Signal<T>::connect() which accepts an event loop
1260 ("context") where the handler will be asked to run.
1263 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1264 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1265 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1266 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1267 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1268 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1269 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1270 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1271 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1272 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1273 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1274 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1275 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1276 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1278 playhead_cursor->show ();
1280 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1281 Config->map_parameters (pc);
1282 _session->config.map_parameters (pc);
1284 restore_ruler_visibility ();
1285 //tempo_map_changed (PropertyChange (0));
1286 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1288 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1289 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1292 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1293 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1296 switch (_snap_type) {
1297 case SnapToRegionStart:
1298 case SnapToRegionEnd:
1299 case SnapToRegionSync:
1300 case SnapToRegionBoundary:
1301 build_region_boundary_cache ();
1308 /* register for undo history */
1309 _session->register_with_memento_command_factory(id(), this);
1311 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1313 start_updating_meters ();
1317 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1319 if (a->get_name() == "RegionMenu") {
1320 /* When the main menu's region menu is opened, we setup the actions so that they look right
1321 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1322 so we resensitize all region actions when the entered regionview or the region selection
1323 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1324 happens after the region context menu is opened. So we set a flag here, too.
1328 sensitize_the_right_region_actions ();
1329 _last_region_menu_was_main = true;
1334 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1336 using namespace Menu_Helpers;
1338 void (Editor::*emf)(FadeShape);
1339 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1342 images = &_xfade_in_images;
1343 emf = &Editor::set_fade_in_shape;
1345 images = &_xfade_out_images;
1346 emf = &Editor::set_fade_out_shape;
1351 _("Linear (for highly correlated material)"),
1352 *(*images)[FadeLinear],
1353 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1357 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1361 _("Constant power"),
1362 *(*images)[FadeConstantPower],
1363 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1366 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1371 *(*images)[FadeSymmetric],
1372 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1376 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1381 *(*images)[FadeSlow],
1382 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *(*images)[FadeFast],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1397 /** Pop up a context menu for when the user clicks on a start crossfade */
1399 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1401 using namespace Menu_Helpers;
1402 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1405 MenuList& items (xfade_in_context_menu.items());
1408 if (arv->audio_region()->fade_in_active()) {
1409 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1411 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1414 items.push_back (SeparatorElem());
1415 fill_xfade_menu (items, true);
1417 xfade_in_context_menu.popup (button, time);
1420 /** Pop up a context menu for when the user clicks on an end crossfade */
1422 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1424 using namespace Menu_Helpers;
1425 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1428 MenuList& items (xfade_out_context_menu.items());
1431 if (arv->audio_region()->fade_out_active()) {
1432 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1434 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1437 items.push_back (SeparatorElem());
1438 fill_xfade_menu (items, false);
1440 xfade_out_context_menu.popup (button, time);
1444 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1446 using namespace Menu_Helpers;
1447 Menu* (Editor::*build_menu_function)();
1450 switch (item_type) {
1452 case RegionViewName:
1453 case RegionViewNameHighlight:
1454 case LeftFrameHandle:
1455 case RightFrameHandle:
1456 if (with_selection) {
1457 build_menu_function = &Editor::build_track_selection_context_menu;
1459 build_menu_function = &Editor::build_track_region_context_menu;
1464 if (with_selection) {
1465 build_menu_function = &Editor::build_track_selection_context_menu;
1467 build_menu_function = &Editor::build_track_context_menu;
1472 if (clicked_routeview->track()) {
1473 build_menu_function = &Editor::build_track_context_menu;
1475 build_menu_function = &Editor::build_track_bus_context_menu;
1480 /* probably shouldn't happen but if it does, we don't care */
1484 menu = (this->*build_menu_function)();
1485 menu->set_name ("ArdourContextMenu");
1487 /* now handle specific situations */
1489 switch (item_type) {
1491 case RegionViewName:
1492 case RegionViewNameHighlight:
1493 case LeftFrameHandle:
1494 case RightFrameHandle:
1495 if (!with_selection) {
1496 if (region_edit_menu_split_item) {
1497 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1498 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1500 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1503 if (region_edit_menu_split_multichannel_item) {
1504 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1505 region_edit_menu_split_multichannel_item->set_sensitive (true);
1507 region_edit_menu_split_multichannel_item->set_sensitive (false);
1520 /* probably shouldn't happen but if it does, we don't care */
1524 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1526 /* Bounce to disk */
1528 using namespace Menu_Helpers;
1529 MenuList& edit_items = menu->items();
1531 edit_items.push_back (SeparatorElem());
1533 switch (clicked_routeview->audio_track()->freeze_state()) {
1534 case AudioTrack::NoFreeze:
1535 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1538 case AudioTrack::Frozen:
1539 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1542 case AudioTrack::UnFrozen:
1543 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1549 if (item_type == StreamItem && clicked_routeview) {
1550 clicked_routeview->build_underlay_menu(menu);
1553 /* When the region menu is opened, we setup the actions so that they look right
1556 sensitize_the_right_region_actions ();
1557 _last_region_menu_was_main = false;
1559 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1560 menu->popup (button, time);
1564 Editor::build_track_context_menu ()
1566 using namespace Menu_Helpers;
1568 MenuList& edit_items = track_context_menu.items();
1571 add_dstream_context_items (edit_items);
1572 return &track_context_menu;
1576 Editor::build_track_bus_context_menu ()
1578 using namespace Menu_Helpers;
1580 MenuList& edit_items = track_context_menu.items();
1583 add_bus_context_items (edit_items);
1584 return &track_context_menu;
1588 Editor::build_track_region_context_menu ()
1590 using namespace Menu_Helpers;
1591 MenuList& edit_items = track_region_context_menu.items();
1594 /* we've just cleared the track region context menu, so the menu that these
1595 two items were on will have disappeared; stop them dangling.
1597 region_edit_menu_split_item = 0;
1598 region_edit_menu_split_multichannel_item = 0;
1600 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1603 boost::shared_ptr<Track> tr;
1604 boost::shared_ptr<Playlist> pl;
1606 if ((tr = rtv->track())) {
1607 add_region_context_items (edit_items, tr);
1611 add_dstream_context_items (edit_items);
1613 return &track_region_context_menu;
1617 Editor::analyze_region_selection ()
1619 if (analysis_window == 0) {
1620 analysis_window = new AnalysisWindow();
1623 analysis_window->set_session(_session);
1625 analysis_window->show_all();
1628 analysis_window->set_regionmode();
1629 analysis_window->analyze();
1631 analysis_window->present();
1635 Editor::analyze_range_selection()
1637 if (analysis_window == 0) {
1638 analysis_window = new AnalysisWindow();
1641 analysis_window->set_session(_session);
1643 analysis_window->show_all();
1646 analysis_window->set_rangemode();
1647 analysis_window->analyze();
1649 analysis_window->present();
1653 Editor::build_track_selection_context_menu ()
1655 using namespace Menu_Helpers;
1656 MenuList& edit_items = track_selection_context_menu.items();
1657 edit_items.clear ();
1659 add_selection_context_items (edit_items);
1660 // edit_items.push_back (SeparatorElem());
1661 // add_dstream_context_items (edit_items);
1663 return &track_selection_context_menu;
1667 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1669 using namespace Menu_Helpers;
1671 /* OK, stick the region submenu at the top of the list, and then add
1675 RegionSelection rs = get_regions_from_selection_and_entered ();
1677 string::size_type pos = 0;
1678 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1680 /* we have to hack up the region name because "_" has a special
1681 meaning for menu titles.
1684 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1685 menu_item_name.replace (pos, 1, "__");
1689 if (_popup_region_menu_item == 0) {
1690 _popup_region_menu_item = new MenuItem (menu_item_name);
1691 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1692 _popup_region_menu_item->show ();
1694 _popup_region_menu_item->set_label (menu_item_name);
1697 const framepos_t position = get_preferred_edit_position (false, true);
1699 edit_items.push_back (*_popup_region_menu_item);
1700 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1701 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1703 edit_items.push_back (SeparatorElem());
1706 /** Add context menu items relevant to selection ranges.
1707 * @param edit_items List to add the items to.
1710 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1712 using namespace Menu_Helpers;
1714 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1715 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1717 edit_items.push_back (SeparatorElem());
1718 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1720 edit_items.push_back (SeparatorElem());
1722 edit_items.push_back (
1724 _("Move Range Start to Previous Region Boundary"),
1725 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1729 edit_items.push_back (
1731 _("Move Range Start to Next Region Boundary"),
1732 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1736 edit_items.push_back (
1738 _("Move Range End to Previous Region Boundary"),
1739 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1743 edit_items.push_back (
1745 _("Move Range End to Next Region Boundary"),
1746 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1750 edit_items.push_back (SeparatorElem());
1751 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1752 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1754 edit_items.push_back (SeparatorElem());
1755 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1757 edit_items.push_back (SeparatorElem());
1758 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1759 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1761 edit_items.push_back (SeparatorElem());
1762 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1764 edit_items.push_back (SeparatorElem());
1765 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1766 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1767 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1769 edit_items.push_back (SeparatorElem());
1770 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1771 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1772 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1773 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1774 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1775 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1776 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1782 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1784 using namespace Menu_Helpers;
1788 Menu *play_menu = manage (new Menu);
1789 MenuList& play_items = play_menu->items();
1790 play_menu->set_name ("ArdourContextMenu");
1792 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1793 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1794 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1795 play_items.push_back (SeparatorElem());
1796 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1798 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1802 Menu *select_menu = manage (new Menu);
1803 MenuList& select_items = select_menu->items();
1804 select_menu->set_name ("ArdourContextMenu");
1806 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1807 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1808 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1809 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1810 select_items.push_back (SeparatorElem());
1811 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1812 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1813 select_items.push_back (SeparatorElem());
1814 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1815 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1816 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1817 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1818 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1819 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1820 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1822 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1826 Menu *cutnpaste_menu = manage (new Menu);
1827 MenuList& cutnpaste_items = cutnpaste_menu->items();
1828 cutnpaste_menu->set_name ("ArdourContextMenu");
1830 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1831 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1832 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1834 cutnpaste_items.push_back (SeparatorElem());
1836 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1837 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1839 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1841 /* Adding new material */
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1845 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1849 Menu *nudge_menu = manage (new Menu());
1850 MenuList& nudge_items = nudge_menu->items();
1851 nudge_menu->set_name ("ArdourContextMenu");
1853 edit_items.push_back (SeparatorElem());
1854 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1855 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1856 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1857 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1859 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1863 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1865 using namespace Menu_Helpers;
1869 Menu *play_menu = manage (new Menu);
1870 MenuList& play_items = play_menu->items();
1871 play_menu->set_name ("ArdourContextMenu");
1873 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1874 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1875 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1879 Menu *select_menu = manage (new Menu);
1880 MenuList& select_items = select_menu->items();
1881 select_menu->set_name ("ArdourContextMenu");
1883 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1884 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1885 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1886 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1887 select_items.push_back (SeparatorElem());
1888 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1889 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1890 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1891 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1893 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1897 Menu *cutnpaste_menu = manage (new Menu);
1898 MenuList& cutnpaste_items = cutnpaste_menu->items();
1899 cutnpaste_menu->set_name ("ArdourContextMenu");
1901 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1902 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1903 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1905 Menu *nudge_menu = manage (new Menu());
1906 MenuList& nudge_items = nudge_menu->items();
1907 nudge_menu->set_name ("ArdourContextMenu");
1909 edit_items.push_back (SeparatorElem());
1910 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1911 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1912 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1913 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1915 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1919 Editor::snap_type() const
1925 Editor::snap_mode() const
1931 Editor::set_snap_to (SnapType st)
1933 unsigned int snap_ind = (unsigned int)st;
1937 if (snap_ind > snap_type_strings.size() - 1) {
1939 _snap_type = (SnapType)snap_ind;
1942 string str = snap_type_strings[snap_ind];
1944 if (str != snap_type_selector.get_text()) {
1945 snap_type_selector.set_text (str);
1950 switch (_snap_type) {
1951 case SnapToBeatDiv128:
1952 case SnapToBeatDiv64:
1953 case SnapToBeatDiv32:
1954 case SnapToBeatDiv28:
1955 case SnapToBeatDiv24:
1956 case SnapToBeatDiv20:
1957 case SnapToBeatDiv16:
1958 case SnapToBeatDiv14:
1959 case SnapToBeatDiv12:
1960 case SnapToBeatDiv10:
1961 case SnapToBeatDiv8:
1962 case SnapToBeatDiv7:
1963 case SnapToBeatDiv6:
1964 case SnapToBeatDiv5:
1965 case SnapToBeatDiv4:
1966 case SnapToBeatDiv3:
1967 case SnapToBeatDiv2: {
1968 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
1969 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
1971 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
1972 current_bbt_points_begin, current_bbt_points_end);
1973 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
1974 current_bbt_points_begin, current_bbt_points_end);
1975 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
1979 case SnapToRegionStart:
1980 case SnapToRegionEnd:
1981 case SnapToRegionSync:
1982 case SnapToRegionBoundary:
1983 build_region_boundary_cache ();
1991 SnapChanged (); /* EMIT SIGNAL */
1995 Editor::set_snap_mode (SnapMode mode)
1997 string str = snap_mode_strings[(int)mode];
1999 if (_internal_editing) {
2000 internal_snap_mode = mode;
2002 pre_internal_snap_mode = mode;
2007 if (str != snap_mode_selector.get_text ()) {
2008 snap_mode_selector.set_text (str);
2014 Editor::set_edit_point_preference (EditPoint ep, bool force)
2016 bool changed = (_edit_point != ep);
2019 string str = edit_point_strings[(int)ep];
2021 if (str != edit_point_selector.get_text ()) {
2022 edit_point_selector.set_text (str);
2025 set_canvas_cursor ();
2027 if (!force && !changed) {
2031 const char* action=NULL;
2033 switch (_edit_point) {
2034 case EditAtPlayhead:
2035 action = "edit-at-playhead";
2037 case EditAtSelectedMarker:
2038 action = "edit-at-marker";
2041 action = "edit-at-mouse";
2045 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2047 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2051 bool in_track_canvas;
2053 if (!mouse_frame (foo, in_track_canvas)) {
2054 in_track_canvas = false;
2057 reset_canvas_action_sensitivity (in_track_canvas);
2063 Editor::set_state (const XMLNode& node, int /*version*/)
2065 const XMLProperty* prop;
2072 g.base_width = default_width;
2073 g.base_height = default_height;
2077 if ((geometry = find_named_node (node, "geometry")) != 0) {
2081 if ((prop = geometry->property("x_size")) == 0) {
2082 prop = geometry->property ("x-size");
2085 g.base_width = atoi(prop->value());
2087 if ((prop = geometry->property("y_size")) == 0) {
2088 prop = geometry->property ("y-size");
2091 g.base_height = atoi(prop->value());
2094 if ((prop = geometry->property ("x_pos")) == 0) {
2095 prop = geometry->property ("x-pos");
2098 x = atoi (prop->value());
2101 if ((prop = geometry->property ("y_pos")) == 0) {
2102 prop = geometry->property ("y-pos");
2105 y = atoi (prop->value());
2109 set_default_size (g.base_width, g.base_height);
2112 if (_session && (prop = node.property ("playhead"))) {
2114 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2115 playhead_cursor->set_position (pos);
2117 playhead_cursor->set_position (0);
2120 if ((prop = node.property ("mixer-width"))) {
2121 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2124 if ((prop = node.property ("zoom-focus"))) {
2125 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2128 if ((prop = node.property ("zoom"))) {
2129 /* older versions of ardour used floating point samples_per_pixel */
2130 double f = PBD::atof (prop->value());
2131 reset_zoom (llrintf (f));
2133 reset_zoom (samples_per_pixel);
2136 if ((prop = node.property ("visible-track-count"))) {
2137 set_visible_track_count (PBD::atoi (prop->value()));
2140 if ((prop = node.property ("snap-to"))) {
2141 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2144 if ((prop = node.property ("snap-mode"))) {
2145 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2148 if ((prop = node.property ("internal-snap-to"))) {
2149 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2152 if ((prop = node.property ("internal-snap-mode"))) {
2153 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2156 if ((prop = node.property ("pre-internal-snap-to"))) {
2157 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2161 if ((prop = node.property ("pre-internal-snap-mode"))) {
2162 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2165 if ((prop = node.property ("mouse-mode"))) {
2166 MouseMode m = str2mousemode(prop->value());
2167 set_mouse_mode (m, true);
2169 set_mouse_mode (MouseObject, true);
2172 if ((prop = node.property ("left-frame")) != 0) {
2174 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2178 reset_x_origin (pos);
2182 if ((prop = node.property ("y-origin")) != 0) {
2183 reset_y_origin (atof (prop->value ()));
2186 if ((prop = node.property ("internal-edit"))) {
2187 bool yn = string_is_affirmative (prop->value());
2188 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2190 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2191 tact->set_active (!yn);
2192 tact->set_active (yn);
2196 if ((prop = node.property ("join-object-range"))) {
2197 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2198 bool yn = string_is_affirmative (prop->value());
2200 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2201 tact->set_active (!yn);
2202 tact->set_active (yn);
2204 set_mouse_mode(mouse_mode, true);
2207 if ((prop = node.property ("edit-point"))) {
2208 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2211 if ((prop = node.property ("show-measures"))) {
2212 bool yn = string_is_affirmative (prop->value());
2213 _show_measures = yn;
2214 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2216 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2217 /* do it twice to force the change */
2218 tact->set_active (!yn);
2219 tact->set_active (yn);
2223 if ((prop = node.property ("follow-playhead"))) {
2224 bool yn = string_is_affirmative (prop->value());
2225 set_follow_playhead (yn);
2226 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2228 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2229 if (tact->get_active() != yn) {
2230 tact->set_active (yn);
2235 if ((prop = node.property ("stationary-playhead"))) {
2236 bool yn = string_is_affirmative (prop->value());
2237 set_stationary_playhead (yn);
2238 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2240 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2241 if (tact->get_active() != yn) {
2242 tact->set_active (yn);
2247 if ((prop = node.property ("region-list-sort-type"))) {
2248 RegionListSortType st;
2249 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2252 if ((prop = node.property ("show-editor-mixer"))) {
2254 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2257 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2258 bool yn = string_is_affirmative (prop->value());
2260 /* do it twice to force the change */
2262 tact->set_active (!yn);
2263 tact->set_active (yn);
2266 if ((prop = node.property ("show-editor-list"))) {
2268 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2271 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2272 bool yn = string_is_affirmative (prop->value());
2274 /* do it twice to force the change */
2276 tact->set_active (!yn);
2277 tact->set_active (yn);
2280 if ((prop = node.property (X_("editor-list-page")))) {
2281 _the_notebook.set_current_page (atoi (prop->value ()));
2284 if ((prop = node.property (X_("show-marker-lines")))) {
2285 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2287 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2288 bool yn = string_is_affirmative (prop->value ());
2290 tact->set_active (!yn);
2291 tact->set_active (yn);
2294 XMLNodeList children = node.children ();
2295 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2296 selection->set_state (**i, Stateful::current_state_version);
2297 _regions->set_state (**i);
2300 if ((prop = node.property ("maximised"))) {
2301 bool yn = string_is_affirmative (prop->value());
2302 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2304 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2305 bool fs = tact && tact->get_active();
2307 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2311 if ((prop = node.property ("nudge-clock-value"))) {
2313 sscanf (prop->value().c_str(), "%" PRId64, &f);
2314 nudge_clock->set (f);
2316 nudge_clock->set_mode (AudioClock::Timecode);
2317 nudge_clock->set (_session->frame_rate() * 5, true);
2324 Editor::get_state ()
2326 XMLNode* node = new XMLNode ("Editor");
2329 id().print (buf, sizeof (buf));
2330 node->add_property ("id", buf);
2332 if (is_realized()) {
2333 Glib::RefPtr<Gdk::Window> win = get_window();
2335 int x, y, width, height;
2336 win->get_root_origin(x, y);
2337 win->get_size(width, height);
2339 XMLNode* geometry = new XMLNode ("geometry");
2341 snprintf(buf, sizeof(buf), "%d", width);
2342 geometry->add_property("x-size", string(buf));
2343 snprintf(buf, sizeof(buf), "%d", height);
2344 geometry->add_property("y-size", string(buf));
2345 snprintf(buf, sizeof(buf), "%d", x);
2346 geometry->add_property("x-pos", string(buf));
2347 snprintf(buf, sizeof(buf), "%d", y);
2348 geometry->add_property("y-pos", string(buf));
2349 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2350 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2351 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2352 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2353 geometry->add_property("edit-vertical-pane-pos", string(buf));
2355 node->add_child_nocopy (*geometry);
2358 maybe_add_mixer_strip_width (*node);
2360 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2362 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2363 node->add_property ("zoom", buf);
2364 node->add_property ("snap-to", enum_2_string (_snap_type));
2365 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2366 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2367 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2368 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2369 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2370 node->add_property ("edit-point", enum_2_string (_edit_point));
2371 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2372 node->add_property ("visible-track-count", buf);
2374 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2375 node->add_property ("playhead", buf);
2376 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2377 node->add_property ("left-frame", buf);
2378 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2379 node->add_property ("y-origin", buf);
2381 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2382 node->add_property ("maximised", _maximised ? "yes" : "no");
2383 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2384 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2385 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2386 node->add_property ("mouse-mode", enum2str(mouse_mode));
2387 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2388 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2390 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2392 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2393 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2396 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2398 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2399 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2402 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2403 node->add_property (X_("editor-list-page"), buf);
2405 if (button_bindings) {
2406 XMLNode* bb = new XMLNode (X_("Buttons"));
2407 button_bindings->save (*bb);
2408 node->add_child_nocopy (*bb);
2411 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2413 node->add_child_nocopy (selection->get_state ());
2414 node->add_child_nocopy (_regions->get_state ());
2416 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2417 node->add_property ("nudge-clock-value", buf);
2422 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2423 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2425 * @return pair: TimeAxisView that y is over, layer index.
2427 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2428 * in stacked or expanded region display mode, otherwise 0.
2430 std::pair<TimeAxisView *, double>
2431 Editor::trackview_by_y_position (double y, bool trackview_relative_offset)
2433 if (!trackview_relative_offset) {
2434 y -= _trackview_group->canvas_origin().y;
2438 return std::make_pair ( (TimeAxisView *) 0, 0);
2441 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2443 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2450 return std::make_pair ( (TimeAxisView *) 0, 0);
2453 /** Snap a position to the grid, if appropriate, taking into account current
2454 * grid settings and also the state of any snap modifier keys that may be pressed.
2455 * @param start Position to snap.
2456 * @param event Event to get current key modifier information from, or 0.
2459 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2461 if (!_session || !event) {
2465 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2466 if (_snap_mode == SnapOff) {
2467 snap_to_internal (start, direction, for_mark);
2470 if (_snap_mode != SnapOff) {
2471 snap_to_internal (start, direction, for_mark);
2477 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2479 if (!_session || _snap_mode == SnapOff) {
2483 snap_to_internal (start, direction, for_mark);
2487 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2489 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2490 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2492 switch (_snap_type) {
2493 case SnapToTimecodeFrame:
2494 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2495 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2497 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2501 case SnapToTimecodeSeconds:
2502 if (_session->config.get_timecode_offset_negative()) {
2503 start += _session->config.get_timecode_offset ();
2505 start -= _session->config.get_timecode_offset ();
2507 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2508 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2510 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2513 if (_session->config.get_timecode_offset_negative()) {
2514 start -= _session->config.get_timecode_offset ();
2516 start += _session->config.get_timecode_offset ();
2520 case SnapToTimecodeMinutes:
2521 if (_session->config.get_timecode_offset_negative()) {
2522 start += _session->config.get_timecode_offset ();
2524 start -= _session->config.get_timecode_offset ();
2526 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2527 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2529 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2531 if (_session->config.get_timecode_offset_negative()) {
2532 start -= _session->config.get_timecode_offset ();
2534 start += _session->config.get_timecode_offset ();
2538 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2544 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2546 const framepos_t one_second = _session->frame_rate();
2547 const framepos_t one_minute = _session->frame_rate() * 60;
2548 framepos_t presnap = start;
2552 switch (_snap_type) {
2553 case SnapToTimecodeFrame:
2554 case SnapToTimecodeSeconds:
2555 case SnapToTimecodeMinutes:
2556 return timecode_snap_to_internal (start, direction, for_mark);
2559 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2560 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2562 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2567 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2568 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2570 start = (framepos_t) floor ((double) start / one_second) * one_second;
2575 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2576 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2578 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2583 start = _session->tempo_map().round_to_bar (start, direction);
2587 start = _session->tempo_map().round_to_beat (start, direction);
2590 case SnapToBeatDiv128:
2591 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2593 case SnapToBeatDiv64:
2594 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2596 case SnapToBeatDiv32:
2597 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2599 case SnapToBeatDiv28:
2600 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2602 case SnapToBeatDiv24:
2603 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2605 case SnapToBeatDiv20:
2606 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2608 case SnapToBeatDiv16:
2609 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2611 case SnapToBeatDiv14:
2612 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2614 case SnapToBeatDiv12:
2615 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2617 case SnapToBeatDiv10:
2618 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2620 case SnapToBeatDiv8:
2621 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2623 case SnapToBeatDiv7:
2624 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2626 case SnapToBeatDiv6:
2627 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2629 case SnapToBeatDiv5:
2630 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2632 case SnapToBeatDiv4:
2633 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2635 case SnapToBeatDiv3:
2636 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2638 case SnapToBeatDiv2:
2639 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2647 _session->locations()->marks_either_side (start, before, after);
2649 if (before == max_framepos && after == max_framepos) {
2650 /* No marks to snap to, so just don't snap */
2652 } else if (before == max_framepos) {
2654 } else if (after == max_framepos) {
2656 } else if (before != max_framepos && after != max_framepos) {
2657 /* have before and after */
2658 if ((start - before) < (after - start)) {
2667 case SnapToRegionStart:
2668 case SnapToRegionEnd:
2669 case SnapToRegionSync:
2670 case SnapToRegionBoundary:
2671 if (!region_boundary_cache.empty()) {
2673 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2674 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2676 if (direction > 0) {
2677 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2679 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2682 if (next != region_boundary_cache.begin ()) {
2687 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2688 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2690 if (start > (p + n) / 2) {
2699 switch (_snap_mode) {
2705 if (presnap > start) {
2706 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2710 } else if (presnap < start) {
2711 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2717 /* handled at entry */
2725 Editor::setup_toolbar ()
2727 HBox* mode_box = manage(new HBox);
2728 mode_box->set_border_width (2);
2729 mode_box->set_spacing(4);
2731 HBox* mouse_mode_box = manage (new HBox);
2732 HBox* mouse_mode_hbox = manage (new HBox);
2733 VBox* mouse_mode_vbox = manage (new VBox);
2734 Alignment* mouse_mode_align = manage (new Alignment);
2736 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2737 // mouse_mode_size_group->add_widget (smart_mode_button);
2738 mouse_mode_size_group->add_widget (mouse_move_button);
2739 mouse_mode_size_group->add_widget (mouse_select_button);
2740 mouse_mode_size_group->add_widget (mouse_zoom_button);
2741 mouse_mode_size_group->add_widget (mouse_gain_button);
2742 mouse_mode_size_group->add_widget (mouse_timefx_button);
2743 mouse_mode_size_group->add_widget (mouse_audition_button);
2744 mouse_mode_size_group->add_widget (mouse_draw_button);
2745 mouse_mode_size_group->add_widget (internal_edit_button);
2747 /* make them just a bit bigger */
2748 mouse_move_button.set_size_request (-1, 30);
2750 mouse_mode_hbox->set_spacing (2);
2752 if (!ARDOUR::Profile->get_trx()) {
2753 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2756 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2757 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2758 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2760 if (!ARDOUR::Profile->get_trx()) {
2761 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2762 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2763 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2764 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2765 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2768 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2770 mouse_mode_align->add (*mouse_mode_vbox);
2771 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2773 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2775 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2776 if (!Profile->get_sae()) {
2777 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2779 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2781 edit_mode_selector.set_name ("mouse mode button");
2782 edit_mode_selector.set_size_request (65, -1);
2783 edit_mode_selector.add_elements (ArdourButton::Inset);
2785 if (!ARDOUR::Profile->get_trx()) {
2786 mode_box->pack_start (edit_mode_selector, false, false);
2788 mode_box->pack_start (*mouse_mode_box, false, false);
2790 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2791 _mouse_mode_tearoff->set_name ("MouseModeBase");
2792 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2794 if (Profile->get_sae()) {
2795 _mouse_mode_tearoff->set_can_be_torn_off (false);
2798 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2799 &_mouse_mode_tearoff->tearoff_window()));
2800 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2801 &_mouse_mode_tearoff->tearoff_window(), 1));
2802 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2803 &_mouse_mode_tearoff->tearoff_window()));
2804 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2805 &_mouse_mode_tearoff->tearoff_window(), 1));
2809 _zoom_box.set_spacing (2);
2810 _zoom_box.set_border_width (2);
2814 zoom_in_button.set_name ("zoom button");
2815 // zoom_in_button.add_elements ( ArdourButton::Inset );
2816 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2817 zoom_in_button.set_image(::get_icon ("zoom_in"));
2818 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2819 zoom_in_button.set_related_action (act);
2821 zoom_out_button.set_name ("zoom button");
2822 // zoom_out_button.add_elements ( ArdourButton::Inset );
2823 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2824 zoom_out_button.set_image(::get_icon ("zoom_out"));
2825 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2826 zoom_out_button.set_related_action (act);
2828 zoom_out_full_button.set_name ("zoom button");
2829 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2830 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2831 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2832 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2833 zoom_out_full_button.set_related_action (act);
2835 zoom_focus_selector.set_name ("zoom button");
2836 zoom_focus_selector.set_size_request (80, -1);
2837 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2839 if (!ARDOUR::Profile->get_trx()) {
2840 _zoom_box.pack_start (zoom_out_button, false, false);
2841 _zoom_box.pack_start (zoom_in_button, false, false);
2842 _zoom_box.pack_start (zoom_out_full_button, false, false);
2843 _zoom_box.pack_start (zoom_focus_selector, false, false);
2845 mode_box->pack_start (zoom_out_button, false, false);
2846 mode_box->pack_start (zoom_in_button, false, false);
2849 /* Track zoom buttons */
2850 visible_tracks_selector.set_name ("zoom button");
2851 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2852 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2854 tav_expand_button.set_name ("zoom button");
2855 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2856 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2857 tav_expand_button.set_size_request (-1, 20);
2858 tav_expand_button.set_image(::get_icon ("tav_exp"));
2859 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2860 tav_expand_button.set_related_action (act);
2862 tav_shrink_button.set_name ("zoom button");
2863 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2864 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2865 tav_shrink_button.set_size_request (-1, 20);
2866 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2867 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2868 tav_shrink_button.set_related_action (act);
2870 if (!ARDOUR::Profile->get_trx()) {
2871 _zoom_box.pack_start (visible_tracks_selector);
2873 _zoom_box.pack_start (tav_shrink_button);
2874 _zoom_box.pack_start (tav_expand_button);
2876 if (!ARDOUR::Profile->get_trx()) {
2877 _zoom_tearoff = manage (new TearOff (_zoom_box));
2879 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2880 &_zoom_tearoff->tearoff_window()));
2881 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2882 &_zoom_tearoff->tearoff_window(), 0));
2883 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2884 &_zoom_tearoff->tearoff_window()));
2885 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2886 &_zoom_tearoff->tearoff_window(), 0));
2889 snap_box.set_spacing (2);
2890 snap_box.set_border_width (2);
2892 snap_type_selector.set_name ("mouse mode button");
2893 snap_type_selector.set_size_request (140, -1);
2894 snap_type_selector.add_elements (ArdourButton::Inset);
2896 snap_mode_selector.set_name ("mouse mode button");
2897 snap_mode_selector.set_size_request (85, -1);
2898 snap_mode_selector.add_elements (ArdourButton::Inset);
2900 edit_point_selector.set_name ("mouse mode button");
2901 edit_point_selector.set_size_request (85, -1);
2902 edit_point_selector.add_elements (ArdourButton::Inset);
2904 snap_box.pack_start (snap_mode_selector, false, false);
2905 snap_box.pack_start (snap_type_selector, false, false);
2906 snap_box.pack_start (edit_point_selector, false, false);
2910 HBox *nudge_box = manage (new HBox);
2911 nudge_box->set_spacing (2);
2912 nudge_box->set_border_width (2);
2914 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2915 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2917 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2918 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2920 nudge_box->pack_start (nudge_backward_button, false, false);
2921 nudge_box->pack_start (nudge_forward_button, false, false);
2922 nudge_box->pack_start (*nudge_clock, false, false);
2925 /* Pack everything in... */
2927 HBox* hbox = manage (new HBox);
2928 hbox->set_spacing(10);
2930 _tools_tearoff = manage (new TearOff (*hbox));
2931 _tools_tearoff->set_name ("MouseModeBase");
2932 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2934 if (Profile->get_sae()) {
2935 _tools_tearoff->set_can_be_torn_off (false);
2938 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2939 &_tools_tearoff->tearoff_window()));
2940 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2941 &_tools_tearoff->tearoff_window(), 0));
2942 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2943 &_tools_tearoff->tearoff_window()));
2944 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2945 &_tools_tearoff->tearoff_window(), 0));
2947 toolbar_hbox.set_spacing (10);
2948 toolbar_hbox.set_border_width (1);
2950 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2951 if (!ARDOUR::Profile->get_trx()) {
2952 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2953 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2956 if (!ARDOUR::Profile->get_trx()) {
2957 hbox->pack_start (snap_box, false, false);
2958 if (!Profile->get_small_screen()) {
2959 hbox->pack_start (*nudge_box, false, false);
2961 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2964 hbox->pack_start (panic_box, false, false);
2968 toolbar_base.set_name ("ToolBarBase");
2969 toolbar_base.add (toolbar_hbox);
2971 _toolbar_viewport.add (toolbar_base);
2972 /* stick to the required height but allow width to vary if there's not enough room */
2973 _toolbar_viewport.set_size_request (1, -1);
2975 toolbar_frame.set_shadow_type (SHADOW_OUT);
2976 toolbar_frame.set_name ("BaseFrame");
2977 toolbar_frame.add (_toolbar_viewport);
2981 Editor::build_edit_point_menu ()
2983 using namespace Menu_Helpers;
2985 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
2986 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
2987 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
2991 Editor::build_edit_mode_menu ()
2993 using namespace Menu_Helpers;
2995 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
2996 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
2997 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3001 Editor::build_snap_mode_menu ()
3003 using namespace Menu_Helpers;
3005 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3006 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3007 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3011 Editor::build_snap_type_menu ()
3013 using namespace Menu_Helpers;
3015 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3016 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3017 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3018 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3019 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3020 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3021 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3022 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3023 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3024 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3025 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3026 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3027 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3028 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3029 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3030 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3031 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3032 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3033 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3034 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3035 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3036 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3037 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3038 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3039 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3040 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3041 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3042 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3043 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3044 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3048 Editor::setup_tooltips ()
3050 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3051 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3052 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3053 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3054 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3055 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3056 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3057 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3058 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3059 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3060 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3061 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3062 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3063 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3064 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3065 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3066 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3067 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3068 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3069 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3070 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3071 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3072 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3073 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3077 Editor::convert_drop_to_paths (
3078 vector<string>& paths,
3079 const RefPtr<Gdk::DragContext>& /*context*/,
3082 const SelectionData& data,
3086 if (_session == 0) {
3090 vector<string> uris = data.get_uris();
3094 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3095 are actually URI lists. So do it by hand.
3098 if (data.get_target() != "text/plain") {
3102 /* Parse the "uri-list" format that Nautilus provides,
3103 where each pathname is delimited by \r\n.
3105 THERE MAY BE NO NULL TERMINATING CHAR!!!
3108 string txt = data.get_text();
3112 p = (char *) malloc (txt.length() + 1);
3113 txt.copy (p, txt.length(), 0);
3114 p[txt.length()] = '\0';
3120 while (g_ascii_isspace (*p))
3124 while (*q && (*q != '\n') && (*q != '\r')) {
3131 while (q > p && g_ascii_isspace (*q))
3136 uris.push_back (string (p, q - p + 1));
3140 p = strchr (p, '\n');
3152 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3153 if ((*i).substr (0,7) == "file://") {
3154 paths.push_back (Glib::filename_from_uri (*i));
3162 Editor::new_tempo_section ()
3167 Editor::map_transport_state ()
3169 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3171 if (_session && _session->transport_stopped()) {
3172 have_pending_keyboard_selection = false;
3175 update_loop_range_view ();
3181 Editor::begin_reversible_command (string name)
3184 _session->begin_reversible_command (name);
3189 Editor::begin_reversible_command (GQuark q)
3192 _session->begin_reversible_command (q);
3197 Editor::commit_reversible_command ()
3200 _session->commit_reversible_command ();
3205 Editor::history_changed ()
3209 if (undo_action && _session) {
3210 if (_session->undo_depth() == 0) {
3211 label = S_("Command|Undo");
3213 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3215 undo_action->property_label() = label;
3218 if (redo_action && _session) {
3219 if (_session->redo_depth() == 0) {
3222 label = string_compose(_("Redo (%1)"), _session->next_redo());
3224 redo_action->property_label() = label;
3229 Editor::duplicate_range (bool with_dialog)
3233 RegionSelection rs = get_regions_from_selection_and_entered ();
3235 if ( selection->time.length() == 0 && rs.empty()) {
3241 ArdourDialog win (_("Duplicate"));
3242 Label label (_("Number of duplications:"));
3243 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3244 SpinButton spinner (adjustment, 0.0, 1);
3247 win.get_vbox()->set_spacing (12);
3248 win.get_vbox()->pack_start (hbox);
3249 hbox.set_border_width (6);
3250 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3252 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3253 place, visually. so do this by hand.
3256 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3257 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3258 spinner.grab_focus();
3264 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3265 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3266 win.set_default_response (RESPONSE_ACCEPT);
3268 spinner.grab_focus ();
3270 switch (win.run ()) {
3271 case RESPONSE_ACCEPT:
3277 times = adjustment.get_value();
3280 if ((current_mouse_mode() == Editing::MouseRange)) {
3281 if (selection->time.length()) {
3282 duplicate_selection (times);
3284 } else if (get_smart_mode()) {
3285 if (selection->time.length()) {
3286 duplicate_selection (times);
3288 duplicate_some_regions (rs, times);
3290 duplicate_some_regions (rs, times);
3295 Editor::set_edit_mode (EditMode m)
3297 Config->set_edit_mode (m);
3301 Editor::cycle_edit_mode ()
3303 switch (Config->get_edit_mode()) {
3305 if (Profile->get_sae()) {
3306 Config->set_edit_mode (Lock);
3308 Config->set_edit_mode (Splice);
3312 Config->set_edit_mode (Lock);
3315 Config->set_edit_mode (Slide);
3321 Editor::edit_mode_selection_done ( EditMode m )
3323 Config->set_edit_mode ( m );
3327 Editor::snap_type_selection_done (SnapType snaptype)
3329 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3331 ract->set_active ();
3336 Editor::snap_mode_selection_done (SnapMode mode)
3338 RefPtr<RadioAction> ract = snap_mode_action (mode);
3341 ract->set_active (true);
3346 Editor::cycle_edit_point (bool with_marker)
3348 switch (_edit_point) {
3350 set_edit_point_preference (EditAtPlayhead);
3352 case EditAtPlayhead:
3354 set_edit_point_preference (EditAtSelectedMarker);
3356 set_edit_point_preference (EditAtMouse);
3359 case EditAtSelectedMarker:
3360 set_edit_point_preference (EditAtMouse);
3366 Editor::edit_point_selection_done (EditPoint ep)
3368 set_edit_point_preference ( ep );
3372 Editor::build_zoom_focus_menu ()
3374 using namespace Menu_Helpers;
3376 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3377 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3378 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3379 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3380 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3381 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3385 Editor::zoom_focus_selection_done ( ZoomFocus f )
3387 RefPtr<RadioAction> ract = zoom_focus_action (f);
3389 ract->set_active ();
3394 Editor::build_track_count_menu ()
3396 using namespace Menu_Helpers;
3398 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3399 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3400 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3401 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3402 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3403 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3404 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3405 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3406 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3407 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3408 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3409 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3413 Editor::set_visible_track_count (int32_t n)
3415 _visible_track_count = n;
3417 /* if the canvas hasn't really been allocated any size yet, just
3418 record the desired number of visible tracks and return. when canvas
3419 allocation happens, we will get called again and then we can do the
3423 if (_visible_canvas_height <= 1) {
3430 if (_visible_track_count > 0) {
3431 h = _visible_canvas_height / _visible_track_count;
3432 std::ostringstream s;
3433 s << _visible_track_count;
3435 } else if (_visible_track_count == 0) {
3436 h = _visible_canvas_height / track_views.size();
3439 /* negative value means that the visible track count has
3440 been overridden by explicit track height changes.
3442 visible_tracks_selector.set_text (X_("*"));
3446 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3447 (*i)->set_height (h);
3450 if (str != visible_tracks_selector.get_text()) {
3451 visible_tracks_selector.set_text (str);
3456 Editor::override_visible_track_count ()
3458 _visible_track_count = -_visible_track_count;
3462 Editor::edit_controls_button_release (GdkEventButton* ev)
3464 if (Keyboard::is_context_menu_event (ev)) {
3465 ARDOUR_UI::instance()->add_route (this);
3466 } else if (ev->button == 1) {
3467 selection->clear_tracks ();
3474 Editor::mouse_select_button_release (GdkEventButton* ev)
3476 /* this handles just right-clicks */
3478 if (ev->button != 3) {
3486 Editor::set_zoom_focus (ZoomFocus f)
3488 string str = zoom_focus_strings[(int)f];
3490 if (str != zoom_focus_selector.get_text()) {
3491 zoom_focus_selector.set_text (str);
3494 if (zoom_focus != f) {
3501 Editor::cycle_zoom_focus ()
3503 switch (zoom_focus) {
3505 set_zoom_focus (ZoomFocusRight);
3507 case ZoomFocusRight:
3508 set_zoom_focus (ZoomFocusCenter);
3510 case ZoomFocusCenter:
3511 set_zoom_focus (ZoomFocusPlayhead);
3513 case ZoomFocusPlayhead:
3514 set_zoom_focus (ZoomFocusMouse);
3516 case ZoomFocusMouse:
3517 set_zoom_focus (ZoomFocusEdit);
3520 set_zoom_focus (ZoomFocusLeft);
3526 Editor::ensure_float (Window& win)
3528 win.set_transient_for (*this);
3532 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3534 /* recover or initialize pane positions. do this here rather than earlier because
3535 we don't want the positions to change the child allocations, which they seem to do.
3541 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3550 XMLNode* geometry = find_named_node (*node, "geometry");
3552 if (which == static_cast<Paned*> (&edit_pane)) {
3554 if (done & Horizontal) {
3558 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3559 _notebook_shrunk = string_is_affirmative (prop->value ());
3562 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3563 /* initial allocation is 90% to canvas, 10% to notebook */
3564 pos = (int) floor (alloc.get_width() * 0.90f);
3565 snprintf (buf, sizeof(buf), "%d", pos);
3567 pos = atoi (prop->value());
3570 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3571 edit_pane.set_position (pos);
3574 done = (Pane) (done | Horizontal);
3576 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3578 if (done & Vertical) {
3582 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3583 /* initial allocation is 90% to canvas, 10% to summary */
3584 pos = (int) floor (alloc.get_height() * 0.90f);
3585 snprintf (buf, sizeof(buf), "%d", pos);
3588 pos = atoi (prop->value());
3591 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3592 editor_summary_pane.set_position (pos);
3595 done = (Pane) (done | Vertical);
3600 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3602 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3603 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3604 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3605 top_hbox.remove (toolbar_frame);
3610 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3612 if (toolbar_frame.get_parent() == 0) {
3613 top_hbox.pack_end (toolbar_frame);
3618 Editor::set_show_measures (bool yn)
3620 if (_show_measures != yn) {
3623 if ((_show_measures = yn) == true) {
3625 tempo_lines->show();
3628 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3629 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3631 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3632 draw_measures (begin, end);
3640 Editor::toggle_follow_playhead ()
3642 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3644 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3645 set_follow_playhead (tact->get_active());
3649 /** @param yn true to follow playhead, otherwise false.
3650 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3653 Editor::set_follow_playhead (bool yn, bool catch_up)
3655 if (_follow_playhead != yn) {
3656 if ((_follow_playhead = yn) == true && catch_up) {
3658 reset_x_origin_to_follow_playhead ();
3665 Editor::toggle_stationary_playhead ()
3667 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3669 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3670 set_stationary_playhead (tact->get_active());
3675 Editor::set_stationary_playhead (bool yn)
3677 if (_stationary_playhead != yn) {
3678 if ((_stationary_playhead = yn) == true) {
3680 // FIXME need a 3.0 equivalent of this 2.X call
3681 // update_current_screen ();
3688 Editor::playlist_selector () const
3690 return *_playlist_selector;
3694 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3698 switch (_snap_type) {
3703 case SnapToBeatDiv128:
3706 case SnapToBeatDiv64:
3709 case SnapToBeatDiv32:
3712 case SnapToBeatDiv28:
3715 case SnapToBeatDiv24:
3718 case SnapToBeatDiv20:
3721 case SnapToBeatDiv16:
3724 case SnapToBeatDiv14:
3727 case SnapToBeatDiv12:
3730 case SnapToBeatDiv10:
3733 case SnapToBeatDiv8:
3736 case SnapToBeatDiv7:
3739 case SnapToBeatDiv6:
3742 case SnapToBeatDiv5:
3745 case SnapToBeatDiv4:
3748 case SnapToBeatDiv3:
3751 case SnapToBeatDiv2:
3757 return _session->tempo_map().meter_at (position).divisions_per_bar();
3762 case SnapToTimecodeFrame:
3763 case SnapToTimecodeSeconds:
3764 case SnapToTimecodeMinutes:
3767 case SnapToRegionStart:
3768 case SnapToRegionEnd:
3769 case SnapToRegionSync:
3770 case SnapToRegionBoundary:
3780 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3784 ret = nudge_clock->current_duration (pos);
3785 next = ret + 1; /* XXXX fix me */
3791 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3793 ArdourDialog dialog (_("Playlist Deletion"));
3794 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3795 "If it is kept, its audio files will not be cleaned.\n"
3796 "If it is deleted, audio files used by it alone will be cleaned."),
3799 dialog.set_position (WIN_POS_CENTER);
3800 dialog.get_vbox()->pack_start (label);
3804 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3805 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3806 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3808 switch (dialog.run ()) {
3809 case RESPONSE_ACCEPT:
3810 /* delete the playlist */
3814 case RESPONSE_REJECT:
3815 /* keep the playlist */
3827 Editor::audio_region_selection_covers (framepos_t where)
3829 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3830 if ((*a)->region()->covers (where)) {
3839 Editor::prepare_for_cleanup ()
3841 cut_buffer->clear_regions ();
3842 cut_buffer->clear_playlists ();
3844 selection->clear_regions ();
3845 selection->clear_playlists ();
3847 _regions->suspend_redisplay ();
3851 Editor::finish_cleanup ()
3853 _regions->resume_redisplay ();
3857 Editor::transport_loop_location()
3860 return _session->locations()->auto_loop_location();
3867 Editor::transport_punch_location()
3870 return _session->locations()->auto_punch_location();
3877 Editor::control_layout_scroll (GdkEventScroll* ev)
3879 /* Just forward to the normal canvas scroll method. The coordinate
3880 systems are different but since the canvas is always larger than the
3881 track headers, and aligned with the trackview area, this will work.
3883 In the not too distant future this layout is going away anyway and
3884 headers will be on the canvas.
3886 return canvas_scroll_event (ev);
3890 Editor::session_state_saved (string)
3893 _snapshots->redisplay ();
3897 Editor::update_tearoff_visibility()
3899 bool visible = Config->get_keep_tearoffs();
3900 _mouse_mode_tearoff->set_visible (visible);
3901 _tools_tearoff->set_visible (visible);
3902 if (_zoom_tearoff) {
3903 _zoom_tearoff->set_visible (visible);
3908 Editor::maximise_editing_space ()
3920 Editor::restore_editing_space ()
3932 * Make new playlists for a given track and also any others that belong
3933 * to the same active route group with the `select' property.
3938 Editor::new_playlists (TimeAxisView* v)
3940 begin_reversible_command (_("new playlists"));
3941 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3942 _session->playlists->get (playlists);
3943 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3944 commit_reversible_command ();
3948 * Use a copy of the current playlist for a given track and also any others that belong
3949 * to the same active route group with the `select' property.
3954 Editor::copy_playlists (TimeAxisView* v)
3956 begin_reversible_command (_("copy playlists"));
3957 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3958 _session->playlists->get (playlists);
3959 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3960 commit_reversible_command ();
3963 /** Clear the current playlist for a given track and also any others that belong
3964 * to the same active route group with the `select' property.
3969 Editor::clear_playlists (TimeAxisView* v)
3971 begin_reversible_command (_("clear playlists"));
3972 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3973 _session->playlists->get (playlists);
3974 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
3975 commit_reversible_command ();
3979 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3981 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3985 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3987 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3991 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
3993 atv.clear_playlist ();
3997 Editor::on_key_press_event (GdkEventKey* ev)
3999 return key_press_focus_accelerator_handler (*this, ev);
4003 Editor::on_key_release_event (GdkEventKey* ev)
4005 return Gtk::Window::on_key_release_event (ev);
4006 // return key_press_focus_accelerator_handler (*this, ev);
4009 /** Queue up a change to the viewport x origin.
4010 * @param frame New x origin.
4013 Editor::reset_x_origin (framepos_t frame)
4015 pending_visual_change.add (VisualChange::TimeOrigin);
4016 pending_visual_change.time_origin = frame;
4017 ensure_visual_change_idle_handler ();
4021 Editor::reset_y_origin (double y)
4023 pending_visual_change.add (VisualChange::YOrigin);
4024 pending_visual_change.y_origin = y;
4025 ensure_visual_change_idle_handler ();
4029 Editor::reset_zoom (framecnt_t spp)
4031 clamp_samples_per_pixel (spp);
4033 if (spp == samples_per_pixel) {
4037 pending_visual_change.add (VisualChange::ZoomLevel);
4038 pending_visual_change.samples_per_pixel = spp;
4039 ensure_visual_change_idle_handler ();
4043 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4045 reset_x_origin (frame);
4048 if (!no_save_visual) {
4049 undo_visual_stack.push_back (current_visual_state(false));
4053 Editor::VisualState::VisualState (bool with_tracks)
4054 : gui_state (with_tracks ? new GUIObjectState : 0)
4058 Editor::VisualState::~VisualState ()
4063 Editor::VisualState*
4064 Editor::current_visual_state (bool with_tracks)
4066 VisualState* vs = new VisualState (with_tracks);
4067 vs->y_position = vertical_adjustment.get_value();
4068 vs->samples_per_pixel = samples_per_pixel;
4069 vs->leftmost_frame = leftmost_frame;
4070 vs->zoom_focus = zoom_focus;
4073 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4080 Editor::undo_visual_state ()
4082 if (undo_visual_stack.empty()) {
4086 VisualState* vs = undo_visual_stack.back();
4087 undo_visual_stack.pop_back();
4090 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4092 use_visual_state (*vs);
4096 Editor::redo_visual_state ()
4098 if (redo_visual_stack.empty()) {
4102 VisualState* vs = redo_visual_stack.back();
4103 redo_visual_stack.pop_back();
4105 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4107 use_visual_state (*vs);
4111 Editor::swap_visual_state ()
4113 if (undo_visual_stack.empty()) {
4114 redo_visual_state ();
4116 undo_visual_state ();
4121 Editor::use_visual_state (VisualState& vs)
4123 PBD::Unwinder<bool> nsv (no_save_visual, true);
4125 _routes->suspend_redisplay ();
4127 vertical_adjustment.set_value (vs.y_position);
4129 set_zoom_focus (vs.zoom_focus);
4130 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4133 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4135 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4136 (*i)->reset_visual_state ();
4140 _routes->update_visibility ();
4141 _routes->resume_redisplay ();
4144 /** This is the core function that controls the zoom level of the canvas. It is called
4145 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4146 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4149 Editor::set_samples_per_pixel (framecnt_t spp)
4151 clamp_samples_per_pixel (spp);
4152 samples_per_pixel = spp;
4155 tempo_lines->tempo_map_changed();
4158 /* convert fpu to frame count */
4160 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4162 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4163 zoom_range_clock->set (frames);
4166 bool const showing_time_selection = selection->time.length() > 0;
4168 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4169 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4170 (*i)->reshow_selection (selection->time);
4174 ZoomChanged (); /* EMIT_SIGNAL */
4176 ArdourCanvas::GtkCanvasViewport* c;
4178 c = get_track_canvas();
4180 c->canvas()->zoomed ();
4183 if (playhead_cursor) {
4184 playhead_cursor->set_position (playhead_cursor->current_frame ());
4187 refresh_location_display();
4188 _summary->set_overlays_dirty ();
4190 update_marker_labels ();
4196 Editor::queue_visual_videotimeline_update ()
4199 * pending_visual_change.add (VisualChange::VideoTimeline);
4200 * or maybe even more specific: which videotimeline-image
4201 * currently it calls update_video_timeline() to update
4202 * _all outdated_ images on the video-timeline.
4203 * see 'exposeimg()' in video_image_frame.cc
4205 ensure_visual_change_idle_handler ();
4209 Editor::ensure_visual_change_idle_handler ()
4211 if (pending_visual_change.idle_handler_id < 0) {
4212 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4213 pending_visual_change.being_handled = false;
4218 Editor::_idle_visual_changer (void* arg)
4220 return static_cast<Editor*>(arg)->idle_visual_changer ();
4224 Editor::idle_visual_changer ()
4226 /* set_horizontal_position() below (and maybe other calls) call
4227 gtk_main_iteration(), so it's possible that a signal will be handled
4228 half-way through this method. If this signal wants an
4229 idle_visual_changer we must schedule another one after this one, so
4230 mark the idle_handler_id as -1 here to allow that. Also make a note
4231 that we are doing the visual change, so that changes in response to
4232 super-rapid-screen-update can be dropped if we are still processing
4236 pending_visual_change.idle_handler_id = -1;
4237 pending_visual_change.being_handled = true;
4239 VisualChange vc = pending_visual_change;
4241 pending_visual_change.pending = (VisualChange::Type) 0;
4243 visual_changer (vc);
4245 pending_visual_change.being_handled = false;
4247 return 0; /* this is always a one-shot call */
4251 Editor::visual_changer (const VisualChange& vc)
4253 double const last_time_origin = horizontal_position ();
4255 if (vc.pending & VisualChange::ZoomLevel) {
4256 set_samples_per_pixel (vc.samples_per_pixel);
4258 compute_fixed_ruler_scale ();
4260 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4261 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4263 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4264 current_bbt_points_begin, current_bbt_points_end);
4265 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4266 current_bbt_points_begin, current_bbt_points_end);
4267 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4269 update_video_timeline();
4272 if (vc.pending & VisualChange::TimeOrigin) {
4273 set_horizontal_position (vc.time_origin / samples_per_pixel);
4276 if (vc.pending & VisualChange::YOrigin) {
4277 vertical_adjustment.set_value (vc.y_origin);
4280 if (last_time_origin == horizontal_position ()) {
4281 /* changed signal not emitted */
4282 update_fixed_rulers ();
4283 redisplay_tempo (true);
4286 if (!(vc.pending & VisualChange::ZoomLevel)) {
4287 update_video_timeline();
4290 _summary->set_overlays_dirty ();
4293 struct EditorOrderTimeAxisSorter {
4294 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4295 return a->order () < b->order ();
4300 Editor::sort_track_selection (TrackViewList& sel)
4302 EditorOrderTimeAxisSorter cmp;
4307 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4310 framepos_t where = 0;
4311 EditPoint ep = _edit_point;
4313 if (from_context_menu && (ep == EditAtMouse)) {
4314 return canvas_event_sample (&context_click_event, 0, 0);
4317 if (entered_marker) {
4318 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4319 return entered_marker->position();
4322 if (ignore_playhead && ep == EditAtPlayhead) {
4323 ep = EditAtSelectedMarker;
4327 case EditAtPlayhead:
4328 where = _session->audible_frame();
4329 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4332 case EditAtSelectedMarker:
4333 if (!selection->markers.empty()) {
4335 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4338 where = loc->start();
4342 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4350 if (!mouse_frame (where, ignored)) {
4351 /* XXX not right but what can we do ? */
4355 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4363 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4365 if (!_session) return;
4367 begin_reversible_command (cmd);
4371 if ((tll = transport_loop_location()) == 0) {
4372 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4373 XMLNode &before = _session->locations()->get_state();
4374 _session->locations()->add (loc, true);
4375 _session->set_auto_loop_location (loc);
4376 XMLNode &after = _session->locations()->get_state();
4377 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4379 XMLNode &before = tll->get_state();
4380 tll->set_hidden (false, this);
4381 tll->set (start, end);
4382 XMLNode &after = tll->get_state();
4383 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4386 commit_reversible_command ();
4390 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4392 if (!_session) return;
4394 begin_reversible_command (cmd);
4398 if ((tpl = transport_punch_location()) == 0) {
4399 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4400 XMLNode &before = _session->locations()->get_state();
4401 _session->locations()->add (loc, true);
4402 _session->set_auto_punch_location (loc);
4403 XMLNode &after = _session->locations()->get_state();
4404 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4407 XMLNode &before = tpl->get_state();
4408 tpl->set_hidden (false, this);
4409 tpl->set (start, end);
4410 XMLNode &after = tpl->get_state();
4411 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4414 commit_reversible_command ();
4417 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4418 * @param rs List to which found regions are added.
4419 * @param where Time to look at.
4420 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4423 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4425 const TrackViewList* tracks;
4428 tracks = &track_views;
4433 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4435 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4438 boost::shared_ptr<Track> tr;
4439 boost::shared_ptr<Playlist> pl;
4441 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4443 boost::shared_ptr<RegionList> regions = pl->regions_at (
4444 (framepos_t) floor ( (double) where * tr->speed()));
4446 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4447 RegionView* rv = rtv->view()->find_view (*i);
4458 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4460 const TrackViewList* tracks;
4463 tracks = &track_views;
4468 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4469 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4471 boost::shared_ptr<Track> tr;
4472 boost::shared_ptr<Playlist> pl;
4474 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4476 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4477 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4479 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4481 RegionView* rv = rtv->view()->find_view (*i);
4492 /** Get regions using the following method:
4494 * Make a region list using the selected regions, unless
4495 * the edit point is `mouse' and the mouse is over an unselected
4496 * region. In this case, use just that region.
4498 * If the edit point is not 'mouse', and there are no regions selected,
4499 * search the list of selected tracks and return regions that are under
4500 * the edit point on these tracks. If there are no selected tracks and
4501 * 'No Selection = All Tracks' is active, search all tracks,
4503 * The rationale here is that the mouse edit point is special in that
4504 * its position describes both a time and a track; the other edit
4505 * modes only describe a time. Hence if the edit point is `mouse' we
4506 * ignore selected tracks, as we assume the user means something by
4507 * pointing at a particular track. Also in this case we take note of
4508 * the region directly under the edit point, as there is always just one
4509 * (rather than possibly several with non-mouse edit points).
4513 Editor::get_regions_from_selection_and_edit_point ()
4515 RegionSelection regions;
4517 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4518 regions.add (entered_regionview);
4520 regions = selection->regions;
4524 if (regions.empty() && _edit_point != EditAtMouse) {
4525 TrackViewList tracks = selection->tracks;
4527 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4528 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4529 * is enabled, so consider all tracks
4531 tracks = track_views;
4534 if (!tracks.empty()) {
4535 /* no region selected or entered, but some selected tracks:
4536 * act on all regions on the selected tracks at the edit point
4538 framepos_t const where = get_preferred_edit_position ();
4539 get_regions_at(regions, where, tracks);
4545 /** Start with regions that are selected, or the entered regionview if none are selected.
4546 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4547 * of the regions that we started with.
4551 Editor::get_regions_from_selection_and_entered ()
4553 RegionSelection regions = selection->regions;
4555 if (regions.empty() && entered_regionview) {
4556 regions.add (entered_regionview);
4563 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4565 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4567 RouteTimeAxisView* tatv;
4569 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4571 boost::shared_ptr<Playlist> pl;
4572 vector<boost::shared_ptr<Region> > results;
4574 boost::shared_ptr<Track> tr;
4576 if ((tr = tatv->track()) == 0) {
4581 if ((pl = (tr->playlist())) != 0) {
4582 if (src_comparison) {
4583 pl->get_source_equivalent_regions (region, results);
4585 pl->get_region_list_equivalent_regions (region, results);
4589 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4590 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4591 regions.push_back (marv);
4600 Editor::show_rhythm_ferret ()
4602 if (rhythm_ferret == 0) {
4603 rhythm_ferret = new RhythmFerret(*this);
4606 rhythm_ferret->set_session (_session);
4607 rhythm_ferret->show ();
4608 rhythm_ferret->present ();
4612 Editor::first_idle ()
4614 MessageDialog* dialog = 0;
4616 if (track_views.size() > 1) {
4617 dialog = new MessageDialog (
4619 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4623 ARDOUR_UI::instance()->flush_pending ();
4626 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4630 // first idle adds route children (automation tracks), so we need to redisplay here
4631 _routes->redisplay ();
4638 Editor::_idle_resize (gpointer arg)
4640 return ((Editor*)arg)->idle_resize ();
4644 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4646 if (resize_idle_id < 0) {
4647 resize_idle_id = g_idle_add (_idle_resize, this);
4648 _pending_resize_amount = 0;
4651 /* make a note of the smallest resulting height, so that we can clamp the
4652 lower limit at TimeAxisView::hSmall */
4654 int32_t min_resulting = INT32_MAX;
4656 _pending_resize_amount += h;
4657 _pending_resize_view = view;
4659 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4661 if (selection->tracks.contains (_pending_resize_view)) {
4662 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4663 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4667 if (min_resulting < 0) {
4672 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4673 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4677 /** Handle pending resizing of tracks */
4679 Editor::idle_resize ()
4681 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4683 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4684 selection->tracks.contains (_pending_resize_view)) {
4686 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4687 if (*i != _pending_resize_view) {
4688 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4693 _pending_resize_amount = 0;
4694 _group_tabs->set_dirty ();
4695 resize_idle_id = -1;
4703 ENSURE_GUI_THREAD (*this, &Editor::located);
4706 playhead_cursor->set_position (_session->audible_frame ());
4707 if (_follow_playhead && !_pending_initial_locate) {
4708 reset_x_origin_to_follow_playhead ();
4712 _pending_locate_request = false;
4713 _pending_initial_locate = false;
4717 Editor::region_view_added (RegionView *)
4719 _summary->set_dirty ();
4723 Editor::region_view_removed ()
4725 _summary->set_dirty ();
4729 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4731 TrackViewList::const_iterator j = track_views.begin ();
4732 while (j != track_views.end()) {
4733 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4734 if (rtv && rtv->route() == r) {
4745 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4749 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4750 TimeAxisView* tv = axis_view_from_route (*i);
4760 Editor::add_routes (RouteList& routes)
4762 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4764 RouteTimeAxisView *rtv;
4765 list<RouteTimeAxisView*> new_views;
4767 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4768 boost::shared_ptr<Route> route = (*x);
4770 if (route->is_auditioner() || route->is_monitor()) {
4774 DataType dt = route->input()->default_type();
4776 if (dt == ARDOUR::DataType::AUDIO) {
4777 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4778 rtv->set_route (route);
4779 } else if (dt == ARDOUR::DataType::MIDI) {
4780 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4781 rtv->set_route (route);
4783 throw unknown_type();
4786 new_views.push_back (rtv);
4787 track_views.push_back (rtv);
4789 rtv->effective_gain_display ();
4791 if (internal_editing()) {
4792 rtv->enter_internal_edit_mode ();
4794 rtv->leave_internal_edit_mode ();
4797 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4798 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4801 if (new_views.size() > 0) {
4802 _routes->routes_added (new_views);
4803 _summary->routes_added (new_views);
4806 if (show_editor_mixer_when_tracks_arrive) {
4807 show_editor_mixer (true);
4810 editor_list_button.set_sensitive (true);
4814 Editor::timeaxisview_deleted (TimeAxisView *tv)
4816 if (_session && _session->deletion_in_progress()) {
4817 /* the situation is under control */
4821 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4823 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4825 _routes->route_removed (tv);
4827 if (tv == entered_track) {
4831 TimeAxisView::Children c = tv->get_child_list ();
4832 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4833 if (entered_track == i->get()) {
4838 /* remove it from the list of track views */
4840 TrackViewList::iterator i;
4842 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4843 i = track_views.erase (i);
4846 /* update whatever the current mixer strip is displaying, if revelant */
4848 boost::shared_ptr<Route> route;
4851 route = rtav->route ();
4854 if (current_mixer_strip && current_mixer_strip->route() == route) {
4856 TimeAxisView* next_tv;
4858 if (track_views.empty()) {
4860 } else if (i == track_views.end()) {
4861 next_tv = track_views.front();
4868 set_selected_mixer_strip (*next_tv);
4870 /* make the editor mixer strip go away setting the
4871 * button to inactive (which also unticks the menu option)
4874 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4880 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4882 if (apply_to_selection) {
4883 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4885 TrackSelection::iterator j = i;
4888 hide_track_in_display (*i, false);
4893 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4895 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4896 // this will hide the mixer strip
4897 set_selected_mixer_strip (*tv);
4900 _routes->hide_track_in_display (*tv);
4905 Editor::sync_track_view_list_and_routes ()
4907 track_views = TrackViewList (_routes->views ());
4909 _summary->set_dirty ();
4910 _group_tabs->set_dirty ();
4912 return false; // do not call again (until needed)
4916 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4918 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4923 /** Find a RouteTimeAxisView by the ID of its route */
4925 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4927 RouteTimeAxisView* v;
4929 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4930 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4931 if(v->route()->id() == id) {
4941 Editor::fit_route_group (RouteGroup *g)
4943 TrackViewList ts = axis_views_from_routes (g->route_list ());
4948 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4950 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4953 _session->cancel_audition ();
4957 if (_session->is_auditioning()) {
4958 _session->cancel_audition ();
4959 if (r == last_audition_region) {
4964 _session->audition_region (r);
4965 last_audition_region = r;
4970 Editor::hide_a_region (boost::shared_ptr<Region> r)
4972 r->set_hidden (true);
4976 Editor::show_a_region (boost::shared_ptr<Region> r)
4978 r->set_hidden (false);
4982 Editor::audition_region_from_region_list ()
4984 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4988 Editor::hide_region_from_region_list ()
4990 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
4994 Editor::show_region_in_region_list ()
4996 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5000 Editor::step_edit_status_change (bool yn)
5003 start_step_editing ();
5005 stop_step_editing ();
5010 Editor::start_step_editing ()
5012 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5016 Editor::stop_step_editing ()
5018 step_edit_connection.disconnect ();
5022 Editor::check_step_edit ()
5024 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5025 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5027 mtv->check_step_edit ();
5031 return true; // do it again, till we stop
5035 Editor::scroll_press (Direction dir)
5037 ++_scroll_callbacks;
5039 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5040 /* delay the first auto-repeat */
5046 scroll_backward (1);
5054 scroll_tracks_up_line ();
5058 scroll_tracks_down_line ();
5062 /* do hacky auto-repeat */
5063 if (!_scroll_connection.connected ()) {
5065 _scroll_connection = Glib::signal_timeout().connect (
5066 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5069 _scroll_callbacks = 0;
5076 Editor::scroll_release ()
5078 _scroll_connection.disconnect ();
5081 /** Queue a change for the Editor viewport x origin to follow the playhead */
5083 Editor::reset_x_origin_to_follow_playhead ()
5085 framepos_t const frame = playhead_cursor->current_frame ();
5087 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5089 if (_session->transport_speed() < 0) {
5091 if (frame > (current_page_samples() / 2)) {
5092 center_screen (frame-(current_page_samples()/2));
5094 center_screen (current_page_samples()/2);
5101 if (frame < leftmost_frame) {
5103 if (_session->transport_rolling()) {
5104 /* rolling; end up with the playhead at the right of the page */
5105 l = frame - current_page_samples ();
5107 /* not rolling: end up with the playhead 1/4 of the way along the page */
5108 l = frame - current_page_samples() / 4;
5112 if (_session->transport_rolling()) {
5113 /* rolling: end up with the playhead on the left of the page */
5116 /* not rolling: end up with the playhead 3/4 of the way along the page */
5117 l = frame - 3 * current_page_samples() / 4;
5125 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5131 Editor::super_rapid_screen_update ()
5133 if (!_session || !_session->engine().running()) {
5137 /* METERING / MIXER STRIPS */
5139 /* update track meters, if required */
5140 if (is_mapped() && meters_running) {
5141 RouteTimeAxisView* rtv;
5142 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5143 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5144 rtv->fast_update ();
5149 /* and any current mixer strip */
5150 if (current_mixer_strip) {
5151 current_mixer_strip->fast_update ();
5154 /* PLAYHEAD AND VIEWPORT */
5156 framepos_t const frame = _session->audible_frame();
5158 /* There are a few reasons why we might not update the playhead / viewport stuff:
5160 * 1. we don't update things when there's a pending locate request, otherwise
5161 * when the editor requests a locate there is a chance that this method
5162 * will move the playhead before the locate request is processed, causing
5164 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5165 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5168 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5170 last_update_frame = frame;
5172 if (!_dragging_playhead) {
5173 playhead_cursor->set_position (frame);
5176 if (!_stationary_playhead) {
5178 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5179 /* We only do this if we aren't already
5180 handling a visual change (ie if
5181 pending_visual_change.being_handled is
5182 false) so that these requests don't stack
5183 up there are too many of them to handle in
5186 reset_x_origin_to_follow_playhead ();
5191 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5195 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5196 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5197 if (target <= 0.0) {
5200 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5201 target = (target * 0.15) + (current * 0.85);
5207 set_horizontal_position (current);
5216 Editor::session_going_away ()
5218 _have_idled = false;
5220 _session_connections.drop_connections ();
5222 super_rapid_screen_update_connection.disconnect ();
5224 selection->clear ();
5225 cut_buffer->clear ();
5227 clicked_regionview = 0;
5228 clicked_axisview = 0;
5229 clicked_routeview = 0;
5230 entered_regionview = 0;
5232 last_update_frame = 0;
5235 playhead_cursor->hide ();
5237 /* rip everything out of the list displays */
5241 _route_groups->clear ();
5243 /* do this first so that deleting a track doesn't reset cms to null
5244 and thus cause a leak.
5247 if (current_mixer_strip) {
5248 if (current_mixer_strip->get_parent() != 0) {
5249 global_hpacker.remove (*current_mixer_strip);
5251 delete current_mixer_strip;
5252 current_mixer_strip = 0;
5255 /* delete all trackviews */
5257 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5260 track_views.clear ();
5262 zoom_range_clock->set_session (0);
5263 nudge_clock->set_session (0);
5265 editor_list_button.set_active(false);
5266 editor_list_button.set_sensitive(false);
5268 /* clear tempo/meter rulers */
5269 remove_metric_marks ();
5271 clear_marker_display ();
5273 stop_step_editing ();
5275 /* get rid of any existing editor mixer strip */
5277 WindowTitle title(Glib::get_application_name());
5278 title += _("Editor");
5280 set_title (title.get_string());
5282 SessionHandlePtr::session_going_away ();
5287 Editor::show_editor_list (bool yn)
5290 _the_notebook.show ();
5292 _the_notebook.hide ();
5297 Editor::change_region_layering_order (bool from_context_menu)
5299 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5301 if (!clicked_routeview) {
5302 if (layering_order_editor) {
5303 layering_order_editor->hide ();
5308 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5314 boost::shared_ptr<Playlist> pl = track->playlist();
5320 if (layering_order_editor == 0) {
5321 layering_order_editor = new RegionLayeringOrderEditor (*this);
5324 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5325 layering_order_editor->maybe_present ();
5329 Editor::update_region_layering_order_editor ()
5331 if (layering_order_editor && layering_order_editor->is_visible ()) {
5332 change_region_layering_order (true);
5337 Editor::setup_fade_images ()
5339 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5340 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5341 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5342 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5343 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5345 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5346 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5347 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5348 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5349 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5351 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5352 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5353 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5354 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5355 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5357 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5358 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5359 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5360 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5361 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5365 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5367 Editor::action_menu_item (std::string const & name)
5369 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5372 return *manage (a->create_menu_item ());
5376 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5378 EventBox* b = manage (new EventBox);
5379 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5380 Label* l = manage (new Label (name));
5384 _the_notebook.append_page (widget, *b);
5388 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5390 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5391 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5394 if (ev->type == GDK_2BUTTON_PRESS) {
5396 /* double-click on a notebook tab shrinks or expands the notebook */
5398 if (_notebook_shrunk) {
5399 if (pre_notebook_shrink_pane_width) {
5400 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5402 _notebook_shrunk = false;
5404 pre_notebook_shrink_pane_width = edit_pane.get_position();
5406 /* this expands the LHS of the edit pane to cover the notebook
5407 PAGE but leaves the tabs visible.
5409 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5410 _notebook_shrunk = true;
5418 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5420 using namespace Menu_Helpers;
5422 MenuList& items = _control_point_context_menu.items ();
5425 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5426 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5427 if (!can_remove_control_point (item)) {
5428 items.back().set_sensitive (false);
5431 _control_point_context_menu.popup (event->button.button, event->button.time);
5435 Editor::zoom_vertical_modifier_released()
5437 _stepping_axis_view = 0;