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"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
145 N_("Timecode Frames"),
146 N_("Timecode Seconds"),
147 N_("Timecode Minutes"),
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 pane_size_watcher (Paned* pane)
217 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
221 Quartz: impossible to access
223 so stop that by preventing it from ever getting too narrow. 35
224 pixels is basically a rough guess at the tab width.
229 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
231 gint pos = pane->get_position ();
233 if (pos > max_width_of_lhs) {
234 pane->set_position (max_width_of_lhs);
239 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241 /* time display buttons */
242 , minsec_label (_("Mins:Secs"))
243 , bbt_label (_("Bars:Beats"))
244 , timecode_label (_("Timecode"))
245 , samples_label (_("Samples"))
246 , tempo_label (_("Tempo"))
247 , meter_label (_("Meter"))
248 , mark_label (_("Location Markers"))
249 , range_mark_label (_("Range Markers"))
250 , transport_mark_label (_("Loop/Punch Ranges"))
251 , cd_mark_label (_("CD Markers"))
252 , videotl_label (_("Video Timeline"))
253 , edit_packer (4, 4, true)
255 /* the values here don't matter: layout widgets
256 reset them as needed.
259 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 , horizontal_adjustment (0.0, 0.0, 1e16)
261 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
263 , controls_layout (unused_adjustment, vertical_adjustment)
265 /* tool bar related */
267 , toolbar_selection_clock_table (2,3)
268 , _mouse_mode_tearoff (0)
269 , automation_mode_button (_("mode"))
273 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
278 , meters_running(false)
279 , _pending_locate_request (false)
280 , _pending_initial_locate (false)
281 , _last_cut_copy_source_track (0)
283 , _region_selection_change_updates_region_list (true)
284 , _following_mixer_selection (false)
285 , _control_point_toggled_on_press (false)
286 , _stepping_axis_view (0)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_control_point = 0;
303 last_update_frame = 0;
304 pre_press_cursor = 0;
305 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 build_edit_mode_menu();
321 build_zoom_focus_menu();
322 build_track_count_menu();
323 build_snap_mode_menu();
324 build_snap_type_menu();
325 build_edit_point_menu();
327 snap_threshold = 5.0;
328 bbt_beat_subdivision = 4;
329 _visible_canvas_width = 0;
330 _visible_canvas_height = 0;
331 autoscroll_horizontal_allowed = false;
332 autoscroll_vertical_allowed = false;
337 current_interthread_info = 0;
338 _show_measures = true;
340 show_gain_after_trim = false;
342 have_pending_keyboard_selection = false;
343 _follow_playhead = true;
344 _stationary_playhead = false;
345 editor_ruler_menu = 0;
346 no_ruler_shown_update = false;
348 range_marker_menu = 0;
349 marker_menu_item = 0;
350 tempo_or_meter_marker_menu = 0;
351 transport_marker_menu = 0;
352 new_transport_marker_menu = 0;
353 editor_mixer_strip_width = Wide;
354 show_editor_mixer_when_tracks_arrive = false;
355 region_edit_menu_split_multichannel_item = 0;
356 region_edit_menu_split_item = 0;
359 current_stepping_trackview = 0;
361 entered_regionview = 0;
363 clear_entered_track = false;
366 button_release_can_deselect = true;
367 _dragging_playhead = false;
368 _dragging_edit_point = false;
369 select_new_marker = false;
371 layering_order_editor = 0;
372 no_save_visual = false;
374 within_track_canvas = false;
376 scrubbing_direction = 0;
380 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
381 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
382 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
383 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
384 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
386 zoom_focus = ZoomFocusLeft;
387 _edit_point = EditAtMouse;
388 _internal_editing = false;
389 current_canvas_cursor = 0;
390 _visible_track_count = 16;
392 samples_per_pixel = 2048; /* too early to use reset_zoom () */
394 _scroll_callbacks = 0;
396 bbt_label.set_name ("EditorRulerLabel");
397 bbt_label.set_size_request (-1, (int)timebar_height);
398 bbt_label.set_alignment (1.0, 0.5);
399 bbt_label.set_padding (5,0);
401 bbt_label.set_no_show_all();
402 minsec_label.set_name ("EditorRulerLabel");
403 minsec_label.set_size_request (-1, (int)timebar_height);
404 minsec_label.set_alignment (1.0, 0.5);
405 minsec_label.set_padding (5,0);
406 minsec_label.hide ();
407 minsec_label.set_no_show_all();
408 timecode_label.set_name ("EditorRulerLabel");
409 timecode_label.set_size_request (-1, (int)timebar_height);
410 timecode_label.set_alignment (1.0, 0.5);
411 timecode_label.set_padding (5,0);
412 timecode_label.hide ();
413 timecode_label.set_no_show_all();
414 samples_label.set_name ("EditorRulerLabel");
415 samples_label.set_size_request (-1, (int)timebar_height);
416 samples_label.set_alignment (1.0, 0.5);
417 samples_label.set_padding (5,0);
418 samples_label.hide ();
419 samples_label.set_no_show_all();
421 tempo_label.set_name ("EditorRulerLabel");
422 tempo_label.set_size_request (-1, (int)timebar_height);
423 tempo_label.set_alignment (1.0, 0.5);
424 tempo_label.set_padding (5,0);
426 tempo_label.set_no_show_all();
428 meter_label.set_name ("EditorRulerLabel");
429 meter_label.set_size_request (-1, (int)timebar_height);
430 meter_label.set_alignment (1.0, 0.5);
431 meter_label.set_padding (5,0);
433 meter_label.set_no_show_all();
435 if (Profile->get_trx()) {
436 mark_label.set_text (_("Markers"));
438 mark_label.set_name ("EditorRulerLabel");
439 mark_label.set_size_request (-1, (int)timebar_height);
440 mark_label.set_alignment (1.0, 0.5);
441 mark_label.set_padding (5,0);
443 mark_label.set_no_show_all();
445 cd_mark_label.set_name ("EditorRulerLabel");
446 cd_mark_label.set_size_request (-1, (int)timebar_height);
447 cd_mark_label.set_alignment (1.0, 0.5);
448 cd_mark_label.set_padding (5,0);
449 cd_mark_label.hide();
450 cd_mark_label.set_no_show_all();
452 videotl_bar_height = 4;
453 videotl_label.set_name ("EditorRulerLabel");
454 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
455 videotl_label.set_alignment (1.0, 0.5);
456 videotl_label.set_padding (5,0);
457 videotl_label.hide();
458 videotl_label.set_no_show_all();
460 range_mark_label.set_name ("EditorRulerLabel");
461 range_mark_label.set_size_request (-1, (int)timebar_height);
462 range_mark_label.set_alignment (1.0, 0.5);
463 range_mark_label.set_padding (5,0);
464 range_mark_label.hide();
465 range_mark_label.set_no_show_all();
467 transport_mark_label.set_name ("EditorRulerLabel");
468 transport_mark_label.set_size_request (-1, (int)timebar_height);
469 transport_mark_label.set_alignment (1.0, 0.5);
470 transport_mark_label.set_padding (5,0);
471 transport_mark_label.hide();
472 transport_mark_label.set_no_show_all();
474 initialize_canvas ();
476 _summary = new EditorSummary (this);
478 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
479 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
481 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
483 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
484 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
486 edit_controls_vbox.set_spacing (0);
487 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
488 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
490 HBox* h = manage (new HBox);
491 _group_tabs = new EditorGroupTabs (this);
492 if (!ARDOUR::Profile->get_trx()) {
493 h->pack_start (*_group_tabs, PACK_SHRINK);
495 h->pack_start (edit_controls_vbox);
496 controls_layout.add (*h);
498 controls_layout.set_name ("EditControlsBase");
499 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
500 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
501 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
503 _cursors = new MouseCursors;
504 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
505 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
507 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
509 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
510 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
511 pad_line_1->set_outline_color (0xFF0000FF);
517 edit_packer.set_col_spacings (0);
518 edit_packer.set_row_spacings (0);
519 edit_packer.set_homogeneous (false);
520 edit_packer.set_border_width (0);
521 edit_packer.set_name ("EditorWindow");
523 time_bars_event_box.add (time_bars_vbox);
524 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
525 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
527 /* labels for the time bars */
528 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
530 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
532 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 if (!ARDOUR::Profile->get_trx()) {
598 editor_summary_pane.pack2 (_summary_hbox);
601 edit_pane.pack1 (editor_summary_pane, true, true);
602 if (!ARDOUR::Profile->get_trx()) {
603 edit_pane.pack2 (_the_notebook, false, true);
606 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
608 /* XXX: editor_summary_pane might need similar to the edit_pane */
610 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
612 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
613 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
615 top_hbox.pack_start (toolbar_frame);
617 HBox *hbox = manage (new HBox);
618 hbox->pack_start (edit_pane, true, true);
620 global_vpacker.pack_start (top_hbox, false, false);
621 global_vpacker.pack_start (*hbox, true, true);
623 global_hpacker.pack_start (global_vpacker, true, true);
625 set_name ("EditorWindow");
626 add_accel_group (ActionManager::ui_manager->get_accel_group());
628 status_bar_hpacker.show ();
630 vpacker.pack_end (status_bar_hpacker, false, false);
631 vpacker.pack_end (global_hpacker, true, true);
633 /* register actions now so that set_state() can find them and set toggles/checks etc */
636 /* when we start using our own keybinding system for the editor, this
637 * will be uncommented
643 set_zoom_focus (zoom_focus);
644 set_visible_track_count (_visible_track_count);
645 _snap_type = SnapToBeat;
646 set_snap_to (_snap_type);
647 _snap_mode = SnapOff;
648 set_snap_mode (_snap_mode);
649 set_mouse_mode (MouseObject, true);
650 pre_internal_mouse_mode = MouseObject;
651 pre_internal_snap_type = _snap_type;
652 pre_internal_snap_mode = _snap_mode;
653 internal_snap_type = _snap_type;
654 internal_snap_mode = _snap_mode;
655 set_edit_point_preference (EditAtMouse, true);
657 _playlist_selector = new PlaylistSelector();
658 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
660 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
664 nudge_forward_button.set_name ("nudge button");
665 // nudge_forward_button.add_elements (ArdourButton::Inset);
666 nudge_forward_button.set_image(::get_icon("nudge_right"));
668 nudge_backward_button.set_name ("nudge button");
669 // nudge_backward_button.add_elements (ArdourButton::Inset);
670 nudge_backward_button.set_image(::get_icon("nudge_left"));
672 fade_context_menu.set_name ("ArdourContextMenu");
674 /* icons, titles, WM stuff */
676 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
677 Glib::RefPtr<Gdk::Pixbuf> icon;
679 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
686 window_icons.push_back (icon);
688 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
689 window_icons.push_back (icon);
691 if (!window_icons.empty()) {
692 // set_icon_list (window_icons);
693 set_default_icon_list (window_icons);
696 WindowTitle title(Glib::get_application_name());
697 title += _("Editor");
698 set_title (title.get_string());
699 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
702 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
704 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
705 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
707 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
709 /* allow external control surfaces/protocols to do various things */
711 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
712 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
713 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
714 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
715 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
716 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
717 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
718 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
719 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
720 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
721 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
722 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
723 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
724 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
726 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
727 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
728 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
729 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
730 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
732 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
734 /* problematic: has to return a value and thus cannot be x-thread */
736 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
738 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
739 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
741 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
743 _ignore_region_action = false;
744 _last_region_menu_was_main = false;
745 _popup_region_menu_item = 0;
747 _show_marker_lines = false;
749 /* Button bindings */
751 button_bindings = new Bindings;
753 XMLNode* node = button_settings();
755 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
756 button_bindings->load (**i);
762 /* grab current parameter state */
763 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
764 ARDOUR_UI::config()->map_parameters (pc);
766 setup_fade_images ();
773 delete button_bindings;
775 delete _route_groups;
776 delete _track_canvas_viewport;
781 Editor::button_settings () const
783 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
784 XMLNode* node = find_named_node (*settings, X_("Buttons"));
787 node = new XMLNode (X_("Buttons"));
794 Editor::add_toplevel_controls (Container& cont)
796 vpacker.pack_start (cont, false, false);
801 Editor::get_smart_mode () const
803 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
807 Editor::catch_vanishing_regionview (RegionView *rv)
809 /* note: the selection will take care of the vanishing
810 audioregionview by itself.
813 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
817 if (clicked_regionview == rv) {
818 clicked_regionview = 0;
821 if (entered_regionview == rv) {
822 set_entered_regionview (0);
825 if (!_all_region_actions_sensitized) {
826 sensitize_all_region_actions (true);
831 Editor::set_entered_regionview (RegionView* rv)
833 if (rv == entered_regionview) {
837 if (entered_regionview) {
838 entered_regionview->exited ();
841 entered_regionview = rv;
843 if (entered_regionview != 0) {
844 entered_regionview->entered (internal_editing ());
847 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
848 /* This RegionView entry might have changed what region actions
849 are allowed, so sensitize them all in case a key is pressed.
851 sensitize_all_region_actions (true);
856 Editor::set_entered_track (TimeAxisView* tav)
859 entered_track->exited ();
865 entered_track->entered ();
870 Editor::show_window ()
872 if (!is_visible ()) {
875 /* XXX: this is a bit unfortunate; it would probably
876 be nicer if we could just call show () above rather
877 than needing the show_all ()
880 /* re-hide stuff if necessary */
881 editor_list_button_toggled ();
882 parameter_changed ("show-summary");
883 parameter_changed ("show-group-tabs");
884 parameter_changed ("show-zoom-tools");
886 /* now reset all audio_time_axis heights, because widgets might need
892 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
893 tv = (static_cast<TimeAxisView*>(*i));
897 if (current_mixer_strip) {
898 current_mixer_strip->hide_things ();
899 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
907 Editor::instant_save ()
909 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
914 _session->add_instant_xml(get_state());
916 Config->add_instant_xml(get_state());
921 Editor::control_vertical_zoom_in_all ()
923 tav_zoom_smooth (false, true);
927 Editor::control_vertical_zoom_out_all ()
929 tav_zoom_smooth (true, true);
933 Editor::control_vertical_zoom_in_selected ()
935 tav_zoom_smooth (false, false);
939 Editor::control_vertical_zoom_out_selected ()
941 tav_zoom_smooth (true, false);
945 Editor::control_view (uint32_t view)
947 goto_visual_state (view);
951 Editor::control_unselect ()
953 selection->clear_tracks ();
957 Editor::control_select (uint32_t rid, Selection::Operation op)
959 /* handles the (static) signal from the ControlProtocol class that
960 * requests setting the selected track to a given RID
967 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
973 TimeAxisView* tav = axis_view_from_route (r);
978 selection->add (tav);
980 case Selection::Toggle:
981 selection->toggle (tav);
983 case Selection::Extend:
986 selection->set (tav);
990 selection->clear_tracks ();
995 Editor::control_step_tracks_up ()
997 scroll_tracks_up_line ();
1001 Editor::control_step_tracks_down ()
1003 scroll_tracks_down_line ();
1007 Editor::control_scroll (float fraction)
1009 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1015 double step = fraction * current_page_samples();
1018 _control_scroll_target is an optional<T>
1020 it acts like a pointer to an framepos_t, with
1021 a operator conversion to boolean to check
1022 that it has a value could possibly use
1023 playhead_cursor->current_frame to store the
1024 value and a boolean in the class to know
1025 when it's out of date
1028 if (!_control_scroll_target) {
1029 _control_scroll_target = _session->transport_frame();
1030 _dragging_playhead = true;
1033 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1034 *_control_scroll_target = 0;
1035 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1036 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1038 *_control_scroll_target += (framepos_t) floor (step);
1041 /* move visuals, we'll catch up with it later */
1043 playhead_cursor->set_position (*_control_scroll_target);
1044 UpdateAllTransportClocks (*_control_scroll_target);
1046 if (*_control_scroll_target > (current_page_samples() / 2)) {
1047 /* try to center PH in window */
1048 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1054 Now we do a timeout to actually bring the session to the right place
1055 according to the playhead. This is to avoid reading disk buffers on every
1056 call to control_scroll, which is driven by ScrollTimeline and therefore
1057 probably by a control surface wheel which can generate lots of events.
1059 /* cancel the existing timeout */
1061 control_scroll_connection.disconnect ();
1063 /* add the next timeout */
1065 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1069 Editor::deferred_control_scroll (framepos_t /*target*/)
1071 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1072 // reset for next stream
1073 _control_scroll_target = boost::none;
1074 _dragging_playhead = false;
1079 Editor::access_action (std::string action_group, std::string action_item)
1085 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1088 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1096 Editor::on_realize ()
1098 Window::on_realize ();
1101 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1102 start_lock_event_timing ();
1105 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1109 Editor::start_lock_event_timing ()
1111 /* check if we should lock the GUI every 30 seconds */
1113 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1117 Editor::generic_event_handler (GdkEvent* ev)
1120 case GDK_BUTTON_PRESS:
1121 case GDK_BUTTON_RELEASE:
1122 case GDK_MOTION_NOTIFY:
1124 case GDK_KEY_RELEASE:
1125 gettimeofday (&last_event_time, 0);
1134 Editor::lock_timeout_callback ()
1136 struct timeval now, delta;
1138 gettimeofday (&now, 0);
1140 timersub (&now, &last_event_time, &delta);
1142 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1144 /* don't call again. Returning false will effectively
1145 disconnect us from the timer callback.
1147 unlock() will call start_lock_event_timing() to get things
1157 Editor::map_position_change (framepos_t frame)
1159 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1161 if (_session == 0) {
1165 if (_follow_playhead) {
1166 center_screen (frame);
1169 playhead_cursor->set_position (frame);
1173 Editor::center_screen (framepos_t frame)
1175 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1177 /* if we're off the page, then scroll.
1180 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1181 center_screen_internal (frame, page);
1186 Editor::center_screen_internal (framepos_t frame, float page)
1191 frame -= (framepos_t) page;
1196 reset_x_origin (frame);
1201 Editor::update_title ()
1203 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1206 bool dirty = _session->dirty();
1208 string session_name;
1210 if (_session->snap_name() != _session->name()) {
1211 session_name = _session->snap_name();
1213 session_name = _session->name();
1217 session_name = "*" + session_name;
1220 WindowTitle title(session_name);
1221 title += Glib::get_application_name();
1222 set_title (title.get_string());
1224 /* ::session_going_away() will have taken care of it */
1229 Editor::set_session (Session *t)
1231 SessionHandlePtr::set_session (t);
1237 _playlist_selector->set_session (_session);
1238 nudge_clock->set_session (_session);
1239 _summary->set_session (_session);
1240 _group_tabs->set_session (_session);
1241 _route_groups->set_session (_session);
1242 _regions->set_session (_session);
1243 _snapshots->set_session (_session);
1244 _routes->set_session (_session);
1245 _locations->set_session (_session);
1247 if (rhythm_ferret) {
1248 rhythm_ferret->set_session (_session);
1251 if (analysis_window) {
1252 analysis_window->set_session (_session);
1256 sfbrowser->set_session (_session);
1259 compute_fixed_ruler_scale ();
1261 /* Make sure we have auto loop and auto punch ranges */
1263 Location* loc = _session->locations()->auto_loop_location();
1265 loc->set_name (_("Loop"));
1268 loc = _session->locations()->auto_punch_location();
1271 loc->set_name (_("Punch"));
1274 refresh_location_display ();
1276 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1277 the selected Marker; this needs the LocationMarker list to be available.
1279 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1280 set_state (*node, Stateful::loading_state_version);
1282 /* catch up with the playhead */
1284 _session->request_locate (playhead_cursor->current_frame ());
1285 _pending_initial_locate = true;
1289 /* These signals can all be emitted by a non-GUI thread. Therefore the
1290 handlers for them must not attempt to directly interact with the GUI,
1291 but use PBD::Signal<T>::connect() which accepts an event loop
1292 ("context") where the handler will be asked to run.
1295 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1296 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1297 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1298 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1299 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1300 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1301 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1302 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1303 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1304 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1305 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1306 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1307 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1308 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1310 playhead_cursor->show ();
1312 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1313 Config->map_parameters (pc);
1314 _session->config.map_parameters (pc);
1316 restore_ruler_visibility ();
1317 //tempo_map_changed (PropertyChange (0));
1318 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1320 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1321 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1324 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1325 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1328 switch (_snap_type) {
1329 case SnapToRegionStart:
1330 case SnapToRegionEnd:
1331 case SnapToRegionSync:
1332 case SnapToRegionBoundary:
1333 build_region_boundary_cache ();
1340 /* register for undo history */
1341 _session->register_with_memento_command_factory(id(), this);
1343 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1345 start_updating_meters ();
1349 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1351 if (a->get_name() == "RegionMenu") {
1352 /* When the main menu's region menu is opened, we setup the actions so that they look right
1353 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1354 so we resensitize all region actions when the entered regionview or the region selection
1355 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1356 happens after the region context menu is opened. So we set a flag here, too.
1360 sensitize_the_right_region_actions ();
1361 _last_region_menu_was_main = true;
1366 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1368 using namespace Menu_Helpers;
1370 void (Editor::*emf)(FadeShape);
1371 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1374 images = &_xfade_in_images;
1375 emf = &Editor::set_fade_in_shape;
1377 images = &_xfade_out_images;
1378 emf = &Editor::set_fade_out_shape;
1383 _("Linear (for highly correlated material)"),
1384 *(*images)[FadeLinear],
1385 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 _("Constant power"),
1394 *(*images)[FadeConstantPower],
1395 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1403 *(*images)[FadeSymmetric],
1404 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1408 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1413 *(*images)[FadeSlow],
1414 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1417 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1422 *(*images)[FadeFast],
1423 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1426 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1429 /** Pop up a context menu for when the user clicks on a start crossfade */
1431 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1433 using namespace Menu_Helpers;
1434 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1437 MenuList& items (xfade_in_context_menu.items());
1440 if (arv->audio_region()->fade_in_active()) {
1441 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1443 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1446 items.push_back (SeparatorElem());
1447 fill_xfade_menu (items, true);
1449 xfade_in_context_menu.popup (button, time);
1452 /** Pop up a context menu for when the user clicks on an end crossfade */
1454 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1456 using namespace Menu_Helpers;
1457 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1460 MenuList& items (xfade_out_context_menu.items());
1463 if (arv->audio_region()->fade_out_active()) {
1464 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1466 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1469 items.push_back (SeparatorElem());
1470 fill_xfade_menu (items, false);
1472 xfade_out_context_menu.popup (button, time);
1476 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1478 using namespace Menu_Helpers;
1479 Menu* (Editor::*build_menu_function)();
1482 switch (item_type) {
1484 case RegionViewName:
1485 case RegionViewNameHighlight:
1486 case LeftFrameHandle:
1487 case RightFrameHandle:
1488 if (with_selection) {
1489 build_menu_function = &Editor::build_track_selection_context_menu;
1491 build_menu_function = &Editor::build_track_region_context_menu;
1496 if (with_selection) {
1497 build_menu_function = &Editor::build_track_selection_context_menu;
1499 build_menu_function = &Editor::build_track_context_menu;
1504 if (clicked_routeview->track()) {
1505 build_menu_function = &Editor::build_track_context_menu;
1507 build_menu_function = &Editor::build_track_bus_context_menu;
1512 /* probably shouldn't happen but if it does, we don't care */
1516 menu = (this->*build_menu_function)();
1517 menu->set_name ("ArdourContextMenu");
1519 /* now handle specific situations */
1521 switch (item_type) {
1523 case RegionViewName:
1524 case RegionViewNameHighlight:
1525 case LeftFrameHandle:
1526 case RightFrameHandle:
1527 if (!with_selection) {
1528 if (region_edit_menu_split_item) {
1529 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1530 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1532 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1535 if (region_edit_menu_split_multichannel_item) {
1536 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1537 region_edit_menu_split_multichannel_item->set_sensitive (true);
1539 region_edit_menu_split_multichannel_item->set_sensitive (false);
1552 /* probably shouldn't happen but if it does, we don't care */
1556 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1558 /* Bounce to disk */
1560 using namespace Menu_Helpers;
1561 MenuList& edit_items = menu->items();
1563 edit_items.push_back (SeparatorElem());
1565 switch (clicked_routeview->audio_track()->freeze_state()) {
1566 case AudioTrack::NoFreeze:
1567 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1570 case AudioTrack::Frozen:
1571 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1574 case AudioTrack::UnFrozen:
1575 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1581 if (item_type == StreamItem && clicked_routeview) {
1582 clicked_routeview->build_underlay_menu(menu);
1585 /* When the region menu is opened, we setup the actions so that they look right
1588 sensitize_the_right_region_actions ();
1589 _last_region_menu_was_main = false;
1591 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1592 menu->popup (button, time);
1596 Editor::build_track_context_menu ()
1598 using namespace Menu_Helpers;
1600 MenuList& edit_items = track_context_menu.items();
1603 add_dstream_context_items (edit_items);
1604 return &track_context_menu;
1608 Editor::build_track_bus_context_menu ()
1610 using namespace Menu_Helpers;
1612 MenuList& edit_items = track_context_menu.items();
1615 add_bus_context_items (edit_items);
1616 return &track_context_menu;
1620 Editor::build_track_region_context_menu ()
1622 using namespace Menu_Helpers;
1623 MenuList& edit_items = track_region_context_menu.items();
1626 /* we've just cleared the track region context menu, so the menu that these
1627 two items were on will have disappeared; stop them dangling.
1629 region_edit_menu_split_item = 0;
1630 region_edit_menu_split_multichannel_item = 0;
1632 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1635 boost::shared_ptr<Track> tr;
1636 boost::shared_ptr<Playlist> pl;
1638 if ((tr = rtv->track())) {
1639 add_region_context_items (edit_items, tr);
1643 add_dstream_context_items (edit_items);
1645 return &track_region_context_menu;
1649 Editor::analyze_region_selection ()
1651 if (analysis_window == 0) {
1652 analysis_window = new AnalysisWindow();
1655 analysis_window->set_session(_session);
1657 analysis_window->show_all();
1660 analysis_window->set_regionmode();
1661 analysis_window->analyze();
1663 analysis_window->present();
1667 Editor::analyze_range_selection()
1669 if (analysis_window == 0) {
1670 analysis_window = new AnalysisWindow();
1673 analysis_window->set_session(_session);
1675 analysis_window->show_all();
1678 analysis_window->set_rangemode();
1679 analysis_window->analyze();
1681 analysis_window->present();
1685 Editor::build_track_selection_context_menu ()
1687 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_selection_context_menu.items();
1689 edit_items.clear ();
1691 add_selection_context_items (edit_items);
1692 // edit_items.push_back (SeparatorElem());
1693 // add_dstream_context_items (edit_items);
1695 return &track_selection_context_menu;
1699 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1701 using namespace Menu_Helpers;
1703 /* OK, stick the region submenu at the top of the list, and then add
1707 RegionSelection rs = get_regions_from_selection_and_entered ();
1709 string::size_type pos = 0;
1710 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1712 /* we have to hack up the region name because "_" has a special
1713 meaning for menu titles.
1716 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1717 menu_item_name.replace (pos, 1, "__");
1721 if (_popup_region_menu_item == 0) {
1722 _popup_region_menu_item = new MenuItem (menu_item_name);
1723 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1724 _popup_region_menu_item->show ();
1726 _popup_region_menu_item->set_label (menu_item_name);
1729 const framepos_t position = get_preferred_edit_position (false, true);
1731 edit_items.push_back (*_popup_region_menu_item);
1732 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1733 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1735 edit_items.push_back (SeparatorElem());
1738 /** Add context menu items relevant to selection ranges.
1739 * @param edit_items List to add the items to.
1742 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1744 using namespace Menu_Helpers;
1746 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1747 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1749 edit_items.push_back (SeparatorElem());
1750 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1752 edit_items.push_back (SeparatorElem());
1754 edit_items.push_back (
1756 _("Move Range Start to Previous Region Boundary"),
1757 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1761 edit_items.push_back (
1763 _("Move Range Start to Next Region Boundary"),
1764 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1768 edit_items.push_back (
1770 _("Move Range End to Previous Region Boundary"),
1771 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1775 edit_items.push_back (
1777 _("Move Range End to Next Region Boundary"),
1778 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1782 edit_items.push_back (SeparatorElem());
1783 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1784 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1786 edit_items.push_back (SeparatorElem());
1787 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1789 edit_items.push_back (SeparatorElem());
1790 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1791 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1793 edit_items.push_back (SeparatorElem());
1794 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1796 edit_items.push_back (SeparatorElem());
1797 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1798 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1799 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1801 edit_items.push_back (SeparatorElem());
1802 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1803 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1804 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1805 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1806 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1807 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1808 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1814 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1816 using namespace Menu_Helpers;
1820 Menu *play_menu = manage (new Menu);
1821 MenuList& play_items = play_menu->items();
1822 play_menu->set_name ("ArdourContextMenu");
1824 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1825 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1826 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1827 play_items.push_back (SeparatorElem());
1828 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1830 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1834 Menu *select_menu = manage (new Menu);
1835 MenuList& select_items = select_menu->items();
1836 select_menu->set_name ("ArdourContextMenu");
1838 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1839 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1840 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1841 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1842 select_items.push_back (SeparatorElem());
1843 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1844 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1845 select_items.push_back (SeparatorElem());
1846 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1847 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1848 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1849 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1850 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1851 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1852 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1854 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1858 Menu *cutnpaste_menu = manage (new Menu);
1859 MenuList& cutnpaste_items = cutnpaste_menu->items();
1860 cutnpaste_menu->set_name ("ArdourContextMenu");
1862 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1863 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1864 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1866 cutnpaste_items.push_back (SeparatorElem());
1868 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1869 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1871 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1873 /* Adding new material */
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1877 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1881 Menu *nudge_menu = manage (new Menu());
1882 MenuList& nudge_items = nudge_menu->items();
1883 nudge_menu->set_name ("ArdourContextMenu");
1885 edit_items.push_back (SeparatorElem());
1886 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1887 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1888 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1889 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1891 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1895 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1897 using namespace Menu_Helpers;
1901 Menu *play_menu = manage (new Menu);
1902 MenuList& play_items = play_menu->items();
1903 play_menu->set_name ("ArdourContextMenu");
1905 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1906 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1907 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1911 Menu *select_menu = manage (new Menu);
1912 MenuList& select_items = select_menu->items();
1913 select_menu->set_name ("ArdourContextMenu");
1915 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1916 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1917 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1918 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1921 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1922 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1925 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1929 Menu *cutnpaste_menu = manage (new Menu);
1930 MenuList& cutnpaste_items = cutnpaste_menu->items();
1931 cutnpaste_menu->set_name ("ArdourContextMenu");
1933 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1934 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1935 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1937 Menu *nudge_menu = manage (new Menu());
1938 MenuList& nudge_items = nudge_menu->items();
1939 nudge_menu->set_name ("ArdourContextMenu");
1941 edit_items.push_back (SeparatorElem());
1942 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1943 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1947 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1951 Editor::snap_type() const
1957 Editor::snap_mode() const
1963 Editor::set_snap_to (SnapType st)
1965 unsigned int snap_ind = (unsigned int)st;
1969 if (snap_ind > snap_type_strings.size() - 1) {
1971 _snap_type = (SnapType)snap_ind;
1974 string str = snap_type_strings[snap_ind];
1976 if (str != snap_type_selector.get_text()) {
1977 snap_type_selector.set_text (str);
1982 switch (_snap_type) {
1983 case SnapToBeatDiv128:
1984 case SnapToBeatDiv64:
1985 case SnapToBeatDiv32:
1986 case SnapToBeatDiv28:
1987 case SnapToBeatDiv24:
1988 case SnapToBeatDiv20:
1989 case SnapToBeatDiv16:
1990 case SnapToBeatDiv14:
1991 case SnapToBeatDiv12:
1992 case SnapToBeatDiv10:
1993 case SnapToBeatDiv8:
1994 case SnapToBeatDiv7:
1995 case SnapToBeatDiv6:
1996 case SnapToBeatDiv5:
1997 case SnapToBeatDiv4:
1998 case SnapToBeatDiv3:
1999 case SnapToBeatDiv2: {
2000 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2001 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2003 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2004 current_bbt_points_begin, current_bbt_points_end);
2005 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2006 current_bbt_points_begin, current_bbt_points_end);
2007 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2011 case SnapToRegionStart:
2012 case SnapToRegionEnd:
2013 case SnapToRegionSync:
2014 case SnapToRegionBoundary:
2015 build_region_boundary_cache ();
2023 SnapChanged (); /* EMIT SIGNAL */
2027 Editor::set_snap_mode (SnapMode mode)
2029 string str = snap_mode_strings[(int)mode];
2031 if (_internal_editing) {
2032 internal_snap_mode = mode;
2034 pre_internal_snap_mode = mode;
2039 if (str != snap_mode_selector.get_text ()) {
2040 snap_mode_selector.set_text (str);
2046 Editor::set_edit_point_preference (EditPoint ep, bool force)
2048 bool changed = (_edit_point != ep);
2051 string str = edit_point_strings[(int)ep];
2053 if (str != edit_point_selector.get_text ()) {
2054 edit_point_selector.set_text (str);
2057 reset_canvas_cursor ();
2059 if (!force && !changed) {
2063 const char* action=NULL;
2065 switch (_edit_point) {
2066 case EditAtPlayhead:
2067 action = "edit-at-playhead";
2069 case EditAtSelectedMarker:
2070 action = "edit-at-marker";
2073 action = "edit-at-mouse";
2077 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2079 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2083 bool in_track_canvas;
2085 if (!mouse_frame (foo, in_track_canvas)) {
2086 in_track_canvas = false;
2089 reset_canvas_action_sensitivity (in_track_canvas);
2095 Editor::set_state (const XMLNode& node, int /*version*/)
2097 const XMLProperty* prop;
2104 g.base_width = default_width;
2105 g.base_height = default_height;
2109 if ((geometry = find_named_node (node, "geometry")) != 0) {
2113 if ((prop = geometry->property("x_size")) == 0) {
2114 prop = geometry->property ("x-size");
2117 g.base_width = atoi(prop->value());
2119 if ((prop = geometry->property("y_size")) == 0) {
2120 prop = geometry->property ("y-size");
2123 g.base_height = atoi(prop->value());
2126 if ((prop = geometry->property ("x_pos")) == 0) {
2127 prop = geometry->property ("x-pos");
2130 x = atoi (prop->value());
2133 if ((prop = geometry->property ("y_pos")) == 0) {
2134 prop = geometry->property ("y-pos");
2137 y = atoi (prop->value());
2141 set_default_size (g.base_width, g.base_height);
2144 if (_session && (prop = node.property ("playhead"))) {
2146 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2147 playhead_cursor->set_position (pos);
2149 playhead_cursor->set_position (0);
2152 if ((prop = node.property ("mixer-width"))) {
2153 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2156 if ((prop = node.property ("zoom-focus"))) {
2157 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2160 if ((prop = node.property ("zoom"))) {
2161 /* older versions of ardour used floating point samples_per_pixel */
2162 double f = PBD::atof (prop->value());
2163 reset_zoom (llrintf (f));
2165 reset_zoom (samples_per_pixel);
2168 if ((prop = node.property ("visible-track-count"))) {
2169 set_visible_track_count (PBD::atoi (prop->value()));
2172 if ((prop = node.property ("snap-to"))) {
2173 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2176 if ((prop = node.property ("snap-mode"))) {
2177 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2180 if ((prop = node.property ("internal-snap-to"))) {
2181 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2184 if ((prop = node.property ("internal-snap-mode"))) {
2185 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2188 if ((prop = node.property ("pre-internal-snap-to"))) {
2189 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2193 if ((prop = node.property ("pre-internal-snap-mode"))) {
2194 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2197 if ((prop = node.property ("mouse-mode"))) {
2198 MouseMode m = str2mousemode(prop->value());
2199 set_mouse_mode (m, true);
2201 set_mouse_mode (MouseObject, true);
2204 if ((prop = node.property ("left-frame")) != 0) {
2206 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2210 reset_x_origin (pos);
2214 if ((prop = node.property ("y-origin")) != 0) {
2215 reset_y_origin (atof (prop->value ()));
2218 if ((prop = node.property ("internal-edit"))) {
2219 bool yn = string_is_affirmative (prop->value());
2220 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2222 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2223 tact->set_active (!yn);
2224 tact->set_active (yn);
2228 if ((prop = node.property ("join-object-range"))) {
2229 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2230 bool yn = string_is_affirmative (prop->value());
2232 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2233 tact->set_active (!yn);
2234 tact->set_active (yn);
2236 set_mouse_mode(mouse_mode, true);
2239 if ((prop = node.property ("edit-point"))) {
2240 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2243 if ((prop = node.property ("show-measures"))) {
2244 bool yn = string_is_affirmative (prop->value());
2245 _show_measures = yn;
2246 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2248 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2249 /* do it twice to force the change */
2250 tact->set_active (!yn);
2251 tact->set_active (yn);
2255 if ((prop = node.property ("follow-playhead"))) {
2256 bool yn = string_is_affirmative (prop->value());
2257 set_follow_playhead (yn);
2258 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2260 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2261 if (tact->get_active() != yn) {
2262 tact->set_active (yn);
2267 if ((prop = node.property ("stationary-playhead"))) {
2268 bool yn = string_is_affirmative (prop->value());
2269 set_stationary_playhead (yn);
2270 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2272 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2273 if (tact->get_active() != yn) {
2274 tact->set_active (yn);
2279 if ((prop = node.property ("region-list-sort-type"))) {
2280 RegionListSortType st;
2281 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2284 if ((prop = node.property ("show-editor-mixer"))) {
2286 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2289 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2290 bool yn = string_is_affirmative (prop->value());
2292 /* do it twice to force the change */
2294 tact->set_active (!yn);
2295 tact->set_active (yn);
2298 if ((prop = node.property ("show-editor-list"))) {
2300 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2303 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2304 bool yn = string_is_affirmative (prop->value());
2306 /* do it twice to force the change */
2308 tact->set_active (!yn);
2309 tact->set_active (yn);
2312 if ((prop = node.property (X_("editor-list-page")))) {
2313 _the_notebook.set_current_page (atoi (prop->value ()));
2316 if ((prop = node.property (X_("show-marker-lines")))) {
2317 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2319 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2320 bool yn = string_is_affirmative (prop->value ());
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2326 XMLNodeList children = node.children ();
2327 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2328 selection->set_state (**i, Stateful::current_state_version);
2329 _regions->set_state (**i);
2332 if ((prop = node.property ("maximised"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2336 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2337 bool fs = tact && tact->get_active();
2339 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2343 if ((prop = node.property ("nudge-clock-value"))) {
2345 sscanf (prop->value().c_str(), "%" PRId64, &f);
2346 nudge_clock->set (f);
2348 nudge_clock->set_mode (AudioClock::Timecode);
2349 nudge_clock->set (_session->frame_rate() * 5, true);
2356 Editor::get_state ()
2358 XMLNode* node = new XMLNode ("Editor");
2361 id().print (buf, sizeof (buf));
2362 node->add_property ("id", buf);
2364 if (is_realized()) {
2365 Glib::RefPtr<Gdk::Window> win = get_window();
2367 int x, y, width, height;
2368 win->get_root_origin(x, y);
2369 win->get_size(width, height);
2371 XMLNode* geometry = new XMLNode ("geometry");
2373 snprintf(buf, sizeof(buf), "%d", width);
2374 geometry->add_property("x-size", string(buf));
2375 snprintf(buf, sizeof(buf), "%d", height);
2376 geometry->add_property("y-size", string(buf));
2377 snprintf(buf, sizeof(buf), "%d", x);
2378 geometry->add_property("x-pos", string(buf));
2379 snprintf(buf, sizeof(buf), "%d", y);
2380 geometry->add_property("y-pos", string(buf));
2381 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2382 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2383 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2384 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2385 geometry->add_property("edit-vertical-pane-pos", string(buf));
2387 node->add_child_nocopy (*geometry);
2390 maybe_add_mixer_strip_width (*node);
2392 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2394 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2395 node->add_property ("zoom", buf);
2396 node->add_property ("snap-to", enum_2_string (_snap_type));
2397 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2398 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2399 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2400 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2401 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2402 node->add_property ("edit-point", enum_2_string (_edit_point));
2403 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2404 node->add_property ("visible-track-count", buf);
2406 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2407 node->add_property ("playhead", buf);
2408 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2409 node->add_property ("left-frame", buf);
2410 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2411 node->add_property ("y-origin", buf);
2413 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2414 node->add_property ("maximised", _maximised ? "yes" : "no");
2415 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2416 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2417 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2418 node->add_property ("mouse-mode", enum2str(mouse_mode));
2419 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2420 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2422 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2424 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2425 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2428 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2430 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2431 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2434 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2435 node->add_property (X_("editor-list-page"), buf);
2437 if (button_bindings) {
2438 XMLNode* bb = new XMLNode (X_("Buttons"));
2439 button_bindings->save (*bb);
2440 node->add_child_nocopy (*bb);
2443 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2445 node->add_child_nocopy (selection->get_state ());
2446 node->add_child_nocopy (_regions->get_state ());
2448 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2449 node->add_property ("nudge-clock-value", buf);
2454 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2455 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2457 * @return pair: TimeAxisView that y is over, layer index.
2459 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2460 * in stacked or expanded region display mode, otherwise 0.
2462 std::pair<TimeAxisView *, double>
2463 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2465 if (!trackview_relative_offset) {
2466 y -= _trackview_group->canvas_origin().y;
2470 return std::make_pair ( (TimeAxisView *) 0, 0);
2473 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2475 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2482 return std::make_pair ( (TimeAxisView *) 0, 0);
2485 /** Snap a position to the grid, if appropriate, taking into account current
2486 * grid settings and also the state of any snap modifier keys that may be pressed.
2487 * @param start Position to snap.
2488 * @param event Event to get current key modifier information from, or 0.
2491 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2493 if (!_session || !event) {
2497 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2498 if (_snap_mode == SnapOff) {
2499 snap_to_internal (start, direction, for_mark);
2502 if (_snap_mode != SnapOff) {
2503 snap_to_internal (start, direction, for_mark);
2509 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2511 if (!_session || _snap_mode == SnapOff) {
2515 snap_to_internal (start, direction, for_mark);
2519 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2521 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2522 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2524 switch (_snap_type) {
2525 case SnapToTimecodeFrame:
2526 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2527 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2529 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2533 case SnapToTimecodeSeconds:
2534 if (_session->config.get_timecode_offset_negative()) {
2535 start += _session->config.get_timecode_offset ();
2537 start -= _session->config.get_timecode_offset ();
2539 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2540 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2542 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2545 if (_session->config.get_timecode_offset_negative()) {
2546 start -= _session->config.get_timecode_offset ();
2548 start += _session->config.get_timecode_offset ();
2552 case SnapToTimecodeMinutes:
2553 if (_session->config.get_timecode_offset_negative()) {
2554 start += _session->config.get_timecode_offset ();
2556 start -= _session->config.get_timecode_offset ();
2558 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2559 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2561 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2563 if (_session->config.get_timecode_offset_negative()) {
2564 start -= _session->config.get_timecode_offset ();
2566 start += _session->config.get_timecode_offset ();
2570 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2576 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2578 const framepos_t one_second = _session->frame_rate();
2579 const framepos_t one_minute = _session->frame_rate() * 60;
2580 framepos_t presnap = start;
2584 switch (_snap_type) {
2585 case SnapToTimecodeFrame:
2586 case SnapToTimecodeSeconds:
2587 case SnapToTimecodeMinutes:
2588 return timecode_snap_to_internal (start, direction, for_mark);
2591 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2592 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2594 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2599 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2600 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2602 start = (framepos_t) floor ((double) start / one_second) * one_second;
2607 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2608 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2610 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2615 start = _session->tempo_map().round_to_bar (start, direction);
2619 start = _session->tempo_map().round_to_beat (start, direction);
2622 case SnapToBeatDiv128:
2623 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2625 case SnapToBeatDiv64:
2626 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2628 case SnapToBeatDiv32:
2629 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2631 case SnapToBeatDiv28:
2632 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2634 case SnapToBeatDiv24:
2635 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2637 case SnapToBeatDiv20:
2638 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2640 case SnapToBeatDiv16:
2641 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2643 case SnapToBeatDiv14:
2644 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2646 case SnapToBeatDiv12:
2647 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2649 case SnapToBeatDiv10:
2650 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2652 case SnapToBeatDiv8:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2655 case SnapToBeatDiv7:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2658 case SnapToBeatDiv6:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2661 case SnapToBeatDiv5:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2664 case SnapToBeatDiv4:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2667 case SnapToBeatDiv3:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2670 case SnapToBeatDiv2:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2679 _session->locations()->marks_either_side (start, before, after);
2681 if (before == max_framepos && after == max_framepos) {
2682 /* No marks to snap to, so just don't snap */
2684 } else if (before == max_framepos) {
2686 } else if (after == max_framepos) {
2688 } else if (before != max_framepos && after != max_framepos) {
2689 /* have before and after */
2690 if ((start - before) < (after - start)) {
2699 case SnapToRegionStart:
2700 case SnapToRegionEnd:
2701 case SnapToRegionSync:
2702 case SnapToRegionBoundary:
2703 if (!region_boundary_cache.empty()) {
2705 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2706 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2708 if (direction > 0) {
2709 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2711 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2714 if (next != region_boundary_cache.begin ()) {
2719 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2720 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2722 if (start > (p + n) / 2) {
2731 switch (_snap_mode) {
2737 if (presnap > start) {
2738 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2742 } else if (presnap < start) {
2743 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2749 /* handled at entry */
2757 Editor::setup_toolbar ()
2759 HBox* mode_box = manage(new HBox);
2760 mode_box->set_border_width (2);
2761 mode_box->set_spacing(4);
2763 HBox* mouse_mode_box = manage (new HBox);
2764 HBox* mouse_mode_hbox = manage (new HBox);
2765 VBox* mouse_mode_vbox = manage (new VBox);
2766 Alignment* mouse_mode_align = manage (new Alignment);
2768 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2769 // mouse_mode_size_group->add_widget (smart_mode_button);
2770 mouse_mode_size_group->add_widget (mouse_move_button);
2771 mouse_mode_size_group->add_widget (mouse_cut_button);
2772 mouse_mode_size_group->add_widget (mouse_select_button);
2773 mouse_mode_size_group->add_widget (mouse_zoom_button);
2774 mouse_mode_size_group->add_widget (mouse_gain_button);
2775 mouse_mode_size_group->add_widget (mouse_timefx_button);
2776 mouse_mode_size_group->add_widget (mouse_audition_button);
2777 mouse_mode_size_group->add_widget (mouse_draw_button);
2778 mouse_mode_size_group->add_widget (internal_edit_button);
2780 /* make them just a bit bigger */
2781 mouse_move_button.set_size_request (-1, 30);
2783 mouse_mode_hbox->set_spacing (2);
2785 if (!ARDOUR::Profile->get_trx()) {
2786 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2789 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2790 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2791 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2792 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2794 if (!ARDOUR::Profile->get_trx()) {
2795 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2796 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2797 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2798 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2799 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2802 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2804 mouse_mode_align->add (*mouse_mode_vbox);
2805 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2807 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2809 edit_mode_selector.set_name ("mouse mode button");
2810 edit_mode_selector.set_size_request (65, -1);
2811 edit_mode_selector.add_elements (ArdourButton::Inset);
2813 if (!ARDOUR::Profile->get_trx()) {
2814 mode_box->pack_start (edit_mode_selector, false, false);
2816 mode_box->pack_start (*mouse_mode_box, false, false);
2818 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2819 _mouse_mode_tearoff->set_name ("MouseModeBase");
2820 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2822 if (Profile->get_sae()) {
2823 _mouse_mode_tearoff->set_can_be_torn_off (false);
2826 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2827 &_mouse_mode_tearoff->tearoff_window()));
2828 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2829 &_mouse_mode_tearoff->tearoff_window(), 1));
2830 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2831 &_mouse_mode_tearoff->tearoff_window()));
2832 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2833 &_mouse_mode_tearoff->tearoff_window(), 1));
2837 _zoom_box.set_spacing (2);
2838 _zoom_box.set_border_width (2);
2842 zoom_in_button.set_name ("zoom button");
2843 // zoom_in_button.add_elements ( ArdourButton::Inset );
2844 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2845 zoom_in_button.set_image(::get_icon ("zoom_in"));
2846 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2847 zoom_in_button.set_related_action (act);
2849 zoom_out_button.set_name ("zoom button");
2850 // zoom_out_button.add_elements ( ArdourButton::Inset );
2851 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2852 zoom_out_button.set_image(::get_icon ("zoom_out"));
2853 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2854 zoom_out_button.set_related_action (act);
2856 zoom_out_full_button.set_name ("zoom button");
2857 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2858 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2859 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2860 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2861 zoom_out_full_button.set_related_action (act);
2863 zoom_focus_selector.set_name ("zoom button");
2864 zoom_focus_selector.set_size_request (80, -1);
2865 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2867 if (!ARDOUR::Profile->get_trx()) {
2868 _zoom_box.pack_start (zoom_out_button, false, false);
2869 _zoom_box.pack_start (zoom_in_button, false, false);
2870 _zoom_box.pack_start (zoom_out_full_button, false, false);
2871 _zoom_box.pack_start (zoom_focus_selector, false, false);
2873 mode_box->pack_start (zoom_out_button, false, false);
2874 mode_box->pack_start (zoom_in_button, false, false);
2877 /* Track zoom buttons */
2878 visible_tracks_selector.set_name ("zoom button");
2879 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2880 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2882 tav_expand_button.set_name ("zoom button");
2883 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2884 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2885 tav_expand_button.set_size_request (-1, 20);
2886 tav_expand_button.set_image(::get_icon ("tav_exp"));
2887 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2888 tav_expand_button.set_related_action (act);
2890 tav_shrink_button.set_name ("zoom button");
2891 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2892 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2893 tav_shrink_button.set_size_request (-1, 20);
2894 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2895 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2896 tav_shrink_button.set_related_action (act);
2898 if (!ARDOUR::Profile->get_trx()) {
2899 _zoom_box.pack_start (visible_tracks_selector);
2901 _zoom_box.pack_start (tav_shrink_button);
2902 _zoom_box.pack_start (tav_expand_button);
2904 if (!ARDOUR::Profile->get_trx()) {
2905 _zoom_tearoff = manage (new TearOff (_zoom_box));
2907 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908 &_zoom_tearoff->tearoff_window()));
2909 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910 &_zoom_tearoff->tearoff_window(), 0));
2911 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912 &_zoom_tearoff->tearoff_window()));
2913 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914 &_zoom_tearoff->tearoff_window(), 0));
2917 snap_box.set_spacing (2);
2918 snap_box.set_border_width (2);
2920 snap_type_selector.set_name ("mouse mode button");
2921 snap_type_selector.set_size_request (140, -1);
2922 snap_type_selector.add_elements (ArdourButton::Inset);
2924 snap_mode_selector.set_name ("mouse mode button");
2925 snap_mode_selector.set_size_request (85, -1);
2926 snap_mode_selector.add_elements (ArdourButton::Inset);
2928 edit_point_selector.set_name ("mouse mode button");
2929 edit_point_selector.set_size_request (85, -1);
2930 edit_point_selector.add_elements (ArdourButton::Inset);
2932 snap_box.pack_start (snap_mode_selector, false, false);
2933 snap_box.pack_start (snap_type_selector, false, false);
2934 snap_box.pack_start (edit_point_selector, false, false);
2938 HBox *nudge_box = manage (new HBox);
2939 nudge_box->set_spacing (2);
2940 nudge_box->set_border_width (2);
2942 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2943 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2945 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2946 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2948 nudge_box->pack_start (nudge_backward_button, false, false);
2949 nudge_box->pack_start (nudge_forward_button, false, false);
2950 nudge_box->pack_start (*nudge_clock, false, false);
2953 /* Pack everything in... */
2955 HBox* hbox = manage (new HBox);
2956 hbox->set_spacing(10);
2958 _tools_tearoff = manage (new TearOff (*hbox));
2959 _tools_tearoff->set_name ("MouseModeBase");
2960 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2962 if (Profile->get_sae()) {
2963 _tools_tearoff->set_can_be_torn_off (false);
2966 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2967 &_tools_tearoff->tearoff_window()));
2968 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2969 &_tools_tearoff->tearoff_window(), 0));
2970 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2971 &_tools_tearoff->tearoff_window()));
2972 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2973 &_tools_tearoff->tearoff_window(), 0));
2975 toolbar_hbox.set_spacing (10);
2976 toolbar_hbox.set_border_width (1);
2978 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2979 if (!ARDOUR::Profile->get_trx()) {
2980 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2981 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2984 if (!ARDOUR::Profile->get_trx()) {
2985 hbox->pack_start (snap_box, false, false);
2986 if (!Profile->get_small_screen()) {
2987 hbox->pack_start (*nudge_box, false, false);
2989 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2992 hbox->pack_start (panic_box, false, false);
2996 toolbar_base.set_name ("ToolBarBase");
2997 toolbar_base.add (toolbar_hbox);
2999 _toolbar_viewport.add (toolbar_base);
3000 /* stick to the required height but allow width to vary if there's not enough room */
3001 _toolbar_viewport.set_size_request (1, -1);
3003 toolbar_frame.set_shadow_type (SHADOW_OUT);
3004 toolbar_frame.set_name ("BaseFrame");
3005 toolbar_frame.add (_toolbar_viewport);
3009 Editor::build_edit_point_menu ()
3011 using namespace Menu_Helpers;
3013 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3014 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3015 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3019 Editor::build_edit_mode_menu ()
3021 using namespace Menu_Helpers;
3023 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3024 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3025 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3026 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3030 Editor::build_snap_mode_menu ()
3032 using namespace Menu_Helpers;
3034 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3035 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3036 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3040 Editor::build_snap_type_menu ()
3042 using namespace Menu_Helpers;
3044 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3045 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3046 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3047 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3048 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3049 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3050 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3051 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3052 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3053 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3054 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3055 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3056 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3057 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3058 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3059 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3060 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3061 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3062 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3077 Editor::setup_tooltips ()
3079 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3080 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3081 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3082 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3083 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3084 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3085 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3086 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3087 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3088 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3089 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3090 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3091 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3092 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3093 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3094 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3095 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3096 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3097 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3098 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3099 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3100 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3101 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3102 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3103 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3107 Editor::convert_drop_to_paths (
3108 vector<string>& paths,
3109 const RefPtr<Gdk::DragContext>& /*context*/,
3112 const SelectionData& data,
3116 if (_session == 0) {
3120 vector<string> uris = data.get_uris();
3124 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3125 are actually URI lists. So do it by hand.
3128 if (data.get_target() != "text/plain") {
3132 /* Parse the "uri-list" format that Nautilus provides,
3133 where each pathname is delimited by \r\n.
3135 THERE MAY BE NO NULL TERMINATING CHAR!!!
3138 string txt = data.get_text();
3142 p = (char *) malloc (txt.length() + 1);
3143 txt.copy (p, txt.length(), 0);
3144 p[txt.length()] = '\0';
3150 while (g_ascii_isspace (*p))
3154 while (*q && (*q != '\n') && (*q != '\r')) {
3161 while (q > p && g_ascii_isspace (*q))
3166 uris.push_back (string (p, q - p + 1));
3170 p = strchr (p, '\n');
3182 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3183 if ((*i).substr (0,7) == "file://") {
3184 paths.push_back (Glib::filename_from_uri (*i));
3192 Editor::new_tempo_section ()
3197 Editor::map_transport_state ()
3199 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3201 if (_session && _session->transport_stopped()) {
3202 have_pending_keyboard_selection = false;
3205 update_loop_range_view ();
3211 Editor::begin_reversible_command (string name)
3214 _session->begin_reversible_command (name);
3219 Editor::begin_reversible_command (GQuark q)
3222 _session->begin_reversible_command (q);
3227 Editor::commit_reversible_command ()
3230 _session->commit_reversible_command ();
3235 Editor::history_changed ()
3239 if (undo_action && _session) {
3240 if (_session->undo_depth() == 0) {
3241 label = S_("Command|Undo");
3243 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3245 undo_action->property_label() = label;
3248 if (redo_action && _session) {
3249 if (_session->redo_depth() == 0) {
3252 label = string_compose(_("Redo (%1)"), _session->next_redo());
3254 redo_action->property_label() = label;
3259 Editor::duplicate_range (bool with_dialog)
3263 RegionSelection rs = get_regions_from_selection_and_entered ();
3265 if ( selection->time.length() == 0 && rs.empty()) {
3271 ArdourDialog win (_("Duplicate"));
3272 Label label (_("Number of duplications:"));
3273 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3274 SpinButton spinner (adjustment, 0.0, 1);
3277 win.get_vbox()->set_spacing (12);
3278 win.get_vbox()->pack_start (hbox);
3279 hbox.set_border_width (6);
3280 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3282 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3283 place, visually. so do this by hand.
3286 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3287 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3288 spinner.grab_focus();
3294 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3295 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3296 win.set_default_response (RESPONSE_ACCEPT);
3298 spinner.grab_focus ();
3300 switch (win.run ()) {
3301 case RESPONSE_ACCEPT:
3307 times = adjustment.get_value();
3310 if ((current_mouse_mode() == Editing::MouseRange)) {
3311 if (selection->time.length()) {
3312 duplicate_selection (times);
3314 } else if (get_smart_mode()) {
3315 if (selection->time.length()) {
3316 duplicate_selection (times);
3318 duplicate_some_regions (rs, times);
3320 duplicate_some_regions (rs, times);
3325 Editor::set_edit_mode (EditMode m)
3327 Config->set_edit_mode (m);
3331 Editor::cycle_edit_mode ()
3333 switch (Config->get_edit_mode()) {
3335 if (Profile->get_sae()) {
3336 Config->set_edit_mode (Lock);
3338 Config->set_edit_mode (Ripple);
3343 Config->set_edit_mode (Lock);
3346 Config->set_edit_mode (Slide);
3352 Editor::edit_mode_selection_done ( EditMode m )
3354 Config->set_edit_mode ( m );
3358 Editor::snap_type_selection_done (SnapType snaptype)
3360 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3362 ract->set_active ();
3367 Editor::snap_mode_selection_done (SnapMode mode)
3369 RefPtr<RadioAction> ract = snap_mode_action (mode);
3372 ract->set_active (true);
3377 Editor::cycle_edit_point (bool with_marker)
3379 switch (_edit_point) {
3381 set_edit_point_preference (EditAtPlayhead);
3383 case EditAtPlayhead:
3385 set_edit_point_preference (EditAtSelectedMarker);
3387 set_edit_point_preference (EditAtMouse);
3390 case EditAtSelectedMarker:
3391 set_edit_point_preference (EditAtMouse);
3397 Editor::edit_point_selection_done (EditPoint ep)
3399 set_edit_point_preference ( ep );
3403 Editor::build_zoom_focus_menu ()
3405 using namespace Menu_Helpers;
3407 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3408 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3409 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3410 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3411 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3412 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3416 Editor::zoom_focus_selection_done ( ZoomFocus f )
3418 RefPtr<RadioAction> ract = zoom_focus_action (f);
3420 ract->set_active ();
3425 Editor::build_track_count_menu ()
3427 using namespace Menu_Helpers;
3429 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3430 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3431 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3432 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3433 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3434 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3435 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3436 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3437 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3438 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3439 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3440 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3444 Editor::set_visible_track_count (int32_t n)
3446 _visible_track_count = n;
3448 /* if the canvas hasn't really been allocated any size yet, just
3449 record the desired number of visible tracks and return. when canvas
3450 allocation happens, we will get called again and then we can do the
3454 if (_visible_canvas_height <= 1) {
3461 if (_visible_track_count > 0) {
3462 h = _visible_canvas_height / _visible_track_count;
3463 std::ostringstream s;
3464 s << _visible_track_count;
3466 } else if (_visible_track_count == 0) {
3467 h = _visible_canvas_height / track_views.size();
3470 /* negative value means that the visible track count has
3471 been overridden by explicit track height changes.
3473 visible_tracks_selector.set_text (X_("*"));
3477 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3478 (*i)->set_height (h);
3481 if (str != visible_tracks_selector.get_text()) {
3482 visible_tracks_selector.set_text (str);
3487 Editor::override_visible_track_count ()
3489 _visible_track_count = -_visible_track_count;
3493 Editor::edit_controls_button_release (GdkEventButton* ev)
3495 if (Keyboard::is_context_menu_event (ev)) {
3496 ARDOUR_UI::instance()->add_route (this);
3497 } else if (ev->button == 1) {
3498 selection->clear_tracks ();
3505 Editor::mouse_select_button_release (GdkEventButton* ev)
3507 /* this handles just right-clicks */
3509 if (ev->button != 3) {
3517 Editor::set_zoom_focus (ZoomFocus f)
3519 string str = zoom_focus_strings[(int)f];
3521 if (str != zoom_focus_selector.get_text()) {
3522 zoom_focus_selector.set_text (str);
3525 if (zoom_focus != f) {
3532 Editor::cycle_zoom_focus ()
3534 switch (zoom_focus) {
3536 set_zoom_focus (ZoomFocusRight);
3538 case ZoomFocusRight:
3539 set_zoom_focus (ZoomFocusCenter);
3541 case ZoomFocusCenter:
3542 set_zoom_focus (ZoomFocusPlayhead);
3544 case ZoomFocusPlayhead:
3545 set_zoom_focus (ZoomFocusMouse);
3547 case ZoomFocusMouse:
3548 set_zoom_focus (ZoomFocusEdit);
3551 set_zoom_focus (ZoomFocusLeft);
3557 Editor::ensure_float (Window& win)
3559 win.set_transient_for (*this);
3563 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3565 /* recover or initialize pane positions. do this here rather than earlier because
3566 we don't want the positions to change the child allocations, which they seem to do.
3572 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3581 XMLNode* geometry = find_named_node (*node, "geometry");
3583 if (which == static_cast<Paned*> (&edit_pane)) {
3585 if (done & Horizontal) {
3589 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3590 _notebook_shrunk = string_is_affirmative (prop->value ());
3593 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3594 /* initial allocation is 90% to canvas, 10% to notebook */
3595 pos = (int) floor (alloc.get_width() * 0.90f);
3596 snprintf (buf, sizeof(buf), "%d", pos);
3598 pos = atoi (prop->value());
3601 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3602 edit_pane.set_position (pos);
3605 done = (Pane) (done | Horizontal);
3607 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3609 if (done & Vertical) {
3613 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3614 /* initial allocation is 90% to canvas, 10% to summary */
3615 pos = (int) floor (alloc.get_height() * 0.90f);
3616 snprintf (buf, sizeof(buf), "%d", pos);
3619 pos = atoi (prop->value());
3622 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3623 editor_summary_pane.set_position (pos);
3626 done = (Pane) (done | Vertical);
3631 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3633 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3634 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3635 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3636 top_hbox.remove (toolbar_frame);
3641 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3643 if (toolbar_frame.get_parent() == 0) {
3644 top_hbox.pack_end (toolbar_frame);
3649 Editor::set_show_measures (bool yn)
3651 if (_show_measures != yn) {
3654 if ((_show_measures = yn) == true) {
3656 tempo_lines->show();
3659 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3660 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3662 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3663 draw_measures (begin, end);
3671 Editor::toggle_follow_playhead ()
3673 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3675 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3676 set_follow_playhead (tact->get_active());
3680 /** @param yn true to follow playhead, otherwise false.
3681 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3684 Editor::set_follow_playhead (bool yn, bool catch_up)
3686 if (_follow_playhead != yn) {
3687 if ((_follow_playhead = yn) == true && catch_up) {
3689 reset_x_origin_to_follow_playhead ();
3696 Editor::toggle_stationary_playhead ()
3698 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3700 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3701 set_stationary_playhead (tact->get_active());
3706 Editor::set_stationary_playhead (bool yn)
3708 if (_stationary_playhead != yn) {
3709 if ((_stationary_playhead = yn) == true) {
3711 // FIXME need a 3.0 equivalent of this 2.X call
3712 // update_current_screen ();
3719 Editor::playlist_selector () const
3721 return *_playlist_selector;
3725 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3729 switch (_snap_type) {
3734 case SnapToBeatDiv128:
3737 case SnapToBeatDiv64:
3740 case SnapToBeatDiv32:
3743 case SnapToBeatDiv28:
3746 case SnapToBeatDiv24:
3749 case SnapToBeatDiv20:
3752 case SnapToBeatDiv16:
3755 case SnapToBeatDiv14:
3758 case SnapToBeatDiv12:
3761 case SnapToBeatDiv10:
3764 case SnapToBeatDiv8:
3767 case SnapToBeatDiv7:
3770 case SnapToBeatDiv6:
3773 case SnapToBeatDiv5:
3776 case SnapToBeatDiv4:
3779 case SnapToBeatDiv3:
3782 case SnapToBeatDiv2:
3788 return _session->tempo_map().meter_at (position).divisions_per_bar();
3793 case SnapToTimecodeFrame:
3794 case SnapToTimecodeSeconds:
3795 case SnapToTimecodeMinutes:
3798 case SnapToRegionStart:
3799 case SnapToRegionEnd:
3800 case SnapToRegionSync:
3801 case SnapToRegionBoundary:
3811 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3815 ret = nudge_clock->current_duration (pos);
3816 next = ret + 1; /* XXXX fix me */
3822 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3824 ArdourDialog dialog (_("Playlist Deletion"));
3825 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3826 "If it is kept, its audio files will not be cleaned.\n"
3827 "If it is deleted, audio files used by it alone will be cleaned."),
3830 dialog.set_position (WIN_POS_CENTER);
3831 dialog.get_vbox()->pack_start (label);
3835 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3836 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3837 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3839 switch (dialog.run ()) {
3840 case RESPONSE_ACCEPT:
3841 /* delete the playlist */
3845 case RESPONSE_REJECT:
3846 /* keep the playlist */
3858 Editor::audio_region_selection_covers (framepos_t where)
3860 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3861 if ((*a)->region()->covers (where)) {
3870 Editor::prepare_for_cleanup ()
3872 cut_buffer->clear_regions ();
3873 cut_buffer->clear_playlists ();
3875 selection->clear_regions ();
3876 selection->clear_playlists ();
3878 _regions->suspend_redisplay ();
3882 Editor::finish_cleanup ()
3884 _regions->resume_redisplay ();
3888 Editor::transport_loop_location()
3891 return _session->locations()->auto_loop_location();
3898 Editor::transport_punch_location()
3901 return _session->locations()->auto_punch_location();
3908 Editor::control_layout_scroll (GdkEventScroll* ev)
3910 /* Just forward to the normal canvas scroll method. The coordinate
3911 systems are different but since the canvas is always larger than the
3912 track headers, and aligned with the trackview area, this will work.
3914 In the not too distant future this layout is going away anyway and
3915 headers will be on the canvas.
3917 return canvas_scroll_event (ev, false);
3921 Editor::session_state_saved (string)
3924 _snapshots->redisplay ();
3928 Editor::update_tearoff_visibility()
3930 bool visible = Config->get_keep_tearoffs();
3931 _mouse_mode_tearoff->set_visible (visible);
3932 _tools_tearoff->set_visible (visible);
3933 if (_zoom_tearoff) {
3934 _zoom_tearoff->set_visible (visible);
3939 Editor::maximise_editing_space ()
3951 Editor::restore_editing_space ()
3963 * Make new playlists for a given track and also any others that belong
3964 * to the same active route group with the `select' property.
3969 Editor::new_playlists (TimeAxisView* v)
3971 begin_reversible_command (_("new playlists"));
3972 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3973 _session->playlists->get (playlists);
3974 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3975 commit_reversible_command ();
3979 * Use a copy of the current playlist for a given track and also any others that belong
3980 * to the same active route group with the `select' property.
3985 Editor::copy_playlists (TimeAxisView* v)
3987 begin_reversible_command (_("copy playlists"));
3988 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3989 _session->playlists->get (playlists);
3990 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3991 commit_reversible_command ();
3994 /** Clear the current playlist for a given track and also any others that belong
3995 * to the same active route group with the `select' property.
4000 Editor::clear_playlists (TimeAxisView* v)
4002 begin_reversible_command (_("clear playlists"));
4003 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4004 _session->playlists->get (playlists);
4005 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4006 commit_reversible_command ();
4010 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4012 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4016 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4018 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4022 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4024 atv.clear_playlist ();
4028 Editor::on_key_press_event (GdkEventKey* ev)
4030 return key_press_focus_accelerator_handler (*this, ev);
4034 Editor::on_key_release_event (GdkEventKey* ev)
4036 return Gtk::Window::on_key_release_event (ev);
4037 // return key_press_focus_accelerator_handler (*this, ev);
4040 /** Queue up a change to the viewport x origin.
4041 * @param frame New x origin.
4044 Editor::reset_x_origin (framepos_t frame)
4046 pending_visual_change.add (VisualChange::TimeOrigin);
4047 pending_visual_change.time_origin = frame;
4048 ensure_visual_change_idle_handler ();
4052 Editor::reset_y_origin (double y)
4054 pending_visual_change.add (VisualChange::YOrigin);
4055 pending_visual_change.y_origin = y;
4056 ensure_visual_change_idle_handler ();
4060 Editor::reset_zoom (framecnt_t spp)
4062 if (spp == samples_per_pixel) {
4066 pending_visual_change.add (VisualChange::ZoomLevel);
4067 pending_visual_change.samples_per_pixel = spp;
4068 ensure_visual_change_idle_handler ();
4072 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4074 reset_x_origin (frame);
4077 if (!no_save_visual) {
4078 undo_visual_stack.push_back (current_visual_state(false));
4082 Editor::VisualState::VisualState (bool with_tracks)
4083 : gui_state (with_tracks ? new GUIObjectState : 0)
4087 Editor::VisualState::~VisualState ()
4092 Editor::VisualState*
4093 Editor::current_visual_state (bool with_tracks)
4095 VisualState* vs = new VisualState (with_tracks);
4096 vs->y_position = vertical_adjustment.get_value();
4097 vs->samples_per_pixel = samples_per_pixel;
4098 vs->leftmost_frame = leftmost_frame;
4099 vs->zoom_focus = zoom_focus;
4102 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4109 Editor::undo_visual_state ()
4111 if (undo_visual_stack.empty()) {
4115 VisualState* vs = undo_visual_stack.back();
4116 undo_visual_stack.pop_back();
4119 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4121 use_visual_state (*vs);
4125 Editor::redo_visual_state ()
4127 if (redo_visual_stack.empty()) {
4131 VisualState* vs = redo_visual_stack.back();
4132 redo_visual_stack.pop_back();
4134 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4136 use_visual_state (*vs);
4140 Editor::swap_visual_state ()
4142 if (undo_visual_stack.empty()) {
4143 redo_visual_state ();
4145 undo_visual_state ();
4150 Editor::use_visual_state (VisualState& vs)
4152 PBD::Unwinder<bool> nsv (no_save_visual, true);
4153 DisplaySuspender ds;
4155 vertical_adjustment.set_value (vs.y_position);
4157 set_zoom_focus (vs.zoom_focus);
4158 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4161 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4163 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4164 (*i)->reset_visual_state ();
4168 _routes->update_visibility ();
4171 /** This is the core function that controls the zoom level of the canvas. It is called
4172 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4173 * @param spp new number of samples per pixel
4176 Editor::set_samples_per_pixel (framecnt_t spp)
4182 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4183 const framecnt_t lots_of_pixels = 4000;
4185 /* if the zoom level is greater than what you'd get trying to display 3
4186 * days of audio on a really big screen, then it's too big.
4189 if (spp * lots_of_pixels > three_days) {
4193 samples_per_pixel = spp;
4196 tempo_lines->tempo_map_changed();
4199 bool const showing_time_selection = selection->time.length() > 0;
4201 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4202 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4203 (*i)->reshow_selection (selection->time);
4207 ZoomChanged (); /* EMIT_SIGNAL */
4209 ArdourCanvas::GtkCanvasViewport* c;
4211 c = get_track_canvas();
4213 c->canvas()->zoomed ();
4216 if (playhead_cursor) {
4217 playhead_cursor->set_position (playhead_cursor->current_frame ());
4220 refresh_location_display();
4221 _summary->set_overlays_dirty ();
4223 update_marker_labels ();
4229 Editor::queue_visual_videotimeline_update ()
4232 * pending_visual_change.add (VisualChange::VideoTimeline);
4233 * or maybe even more specific: which videotimeline-image
4234 * currently it calls update_video_timeline() to update
4235 * _all outdated_ images on the video-timeline.
4236 * see 'exposeimg()' in video_image_frame.cc
4238 ensure_visual_change_idle_handler ();
4242 Editor::ensure_visual_change_idle_handler ()
4244 if (pending_visual_change.idle_handler_id < 0) {
4245 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4246 pending_visual_change.being_handled = false;
4251 Editor::_idle_visual_changer (void* arg)
4253 return static_cast<Editor*>(arg)->idle_visual_changer ();
4257 Editor::idle_visual_changer ()
4259 /* set_horizontal_position() below (and maybe other calls) call
4260 gtk_main_iteration(), so it's possible that a signal will be handled
4261 half-way through this method. If this signal wants an
4262 idle_visual_changer we must schedule another one after this one, so
4263 mark the idle_handler_id as -1 here to allow that. Also make a note
4264 that we are doing the visual change, so that changes in response to
4265 super-rapid-screen-update can be dropped if we are still processing
4269 pending_visual_change.idle_handler_id = -1;
4270 pending_visual_change.being_handled = true;
4272 VisualChange vc = pending_visual_change;
4274 pending_visual_change.pending = (VisualChange::Type) 0;
4276 visual_changer (vc);
4278 pending_visual_change.being_handled = false;
4280 return 0; /* this is always a one-shot call */
4284 Editor::visual_changer (const VisualChange& vc)
4286 double const last_time_origin = horizontal_position ();
4288 if (vc.pending & VisualChange::ZoomLevel) {
4289 set_samples_per_pixel (vc.samples_per_pixel);
4291 compute_fixed_ruler_scale ();
4293 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4294 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4296 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4297 current_bbt_points_begin, current_bbt_points_end);
4298 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4299 current_bbt_points_begin, current_bbt_points_end);
4300 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4302 update_video_timeline();
4305 if (vc.pending & VisualChange::TimeOrigin) {
4306 set_horizontal_position (vc.time_origin / samples_per_pixel);
4309 if (vc.pending & VisualChange::YOrigin) {
4310 vertical_adjustment.set_value (vc.y_origin);
4313 if (last_time_origin == horizontal_position ()) {
4314 /* changed signal not emitted */
4315 update_fixed_rulers ();
4316 redisplay_tempo (true);
4319 if (!(vc.pending & VisualChange::ZoomLevel)) {
4320 update_video_timeline();
4323 _summary->set_overlays_dirty ();
4326 struct EditorOrderTimeAxisSorter {
4327 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4328 return a->order () < b->order ();
4333 Editor::sort_track_selection (TrackViewList& sel)
4335 EditorOrderTimeAxisSorter cmp;
4340 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4343 framepos_t where = 0;
4344 EditPoint ep = _edit_point;
4346 if (from_context_menu && (ep == EditAtMouse)) {
4347 return canvas_event_sample (&context_click_event, 0, 0);
4350 if (entered_marker) {
4351 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4352 return entered_marker->position();
4355 if (ignore_playhead && ep == EditAtPlayhead) {
4356 ep = EditAtSelectedMarker;
4360 case EditAtPlayhead:
4361 where = _session->audible_frame();
4362 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4365 case EditAtSelectedMarker:
4366 if (!selection->markers.empty()) {
4368 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4371 where = loc->start();
4375 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4383 if (!mouse_frame (where, ignored)) {
4384 /* XXX not right but what can we do ? */
4388 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4396 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4398 if (!_session) return;
4400 begin_reversible_command (cmd);
4404 if ((tll = transport_loop_location()) == 0) {
4405 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4406 XMLNode &before = _session->locations()->get_state();
4407 _session->locations()->add (loc, true);
4408 _session->set_auto_loop_location (loc);
4409 XMLNode &after = _session->locations()->get_state();
4410 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4412 XMLNode &before = tll->get_state();
4413 tll->set_hidden (false, this);
4414 tll->set (start, end);
4415 XMLNode &after = tll->get_state();
4416 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4419 commit_reversible_command ();
4423 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4425 if (!_session) return;
4427 begin_reversible_command (cmd);
4431 if ((tpl = transport_punch_location()) == 0) {
4432 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4433 XMLNode &before = _session->locations()->get_state();
4434 _session->locations()->add (loc, true);
4435 _session->set_auto_punch_location (loc);
4436 XMLNode &after = _session->locations()->get_state();
4437 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4440 XMLNode &before = tpl->get_state();
4441 tpl->set_hidden (false, this);
4442 tpl->set (start, end);
4443 XMLNode &after = tpl->get_state();
4444 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4447 commit_reversible_command ();
4450 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4451 * @param rs List to which found regions are added.
4452 * @param where Time to look at.
4453 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4456 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4458 const TrackViewList* tracks;
4461 tracks = &track_views;
4466 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4468 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_at (
4477 (framepos_t) floor ( (double) where * tr->speed()));
4479 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4480 RegionView* rv = rtv->view()->find_view (*i);
4491 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4493 const TrackViewList* tracks;
4496 tracks = &track_views;
4501 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4502 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4504 boost::shared_ptr<Track> tr;
4505 boost::shared_ptr<Playlist> pl;
4507 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4509 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4510 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4512 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4514 RegionView* rv = rtv->view()->find_view (*i);
4525 /** Get regions using the following method:
4527 * Make a region list using:
4528 * (a) any selected regions
4529 * (b) the intersection of any selected tracks and the edit point(*)
4530 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4532 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4534 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4538 Editor::get_regions_from_selection_and_edit_point ()
4540 RegionSelection regions;
4542 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4543 regions.add (entered_regionview);
4545 regions = selection->regions;
4548 if ( regions.empty() ) {
4549 TrackViewList tracks = selection->tracks;
4551 if (!tracks.empty()) {
4552 /* no region selected or entered, but some selected tracks:
4553 * act on all regions on the selected tracks at the edit point
4555 framepos_t const where = get_preferred_edit_position ();
4556 get_regions_at(regions, where, tracks);
4563 /** Start with regions that are selected, or the entered regionview if none are selected.
4564 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4565 * of the regions that we started with.
4569 Editor::get_regions_from_selection_and_entered ()
4571 RegionSelection regions = selection->regions;
4573 if (regions.empty() && entered_regionview) {
4574 regions.add (entered_regionview);
4581 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4583 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4585 RouteTimeAxisView* tatv;
4587 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4589 boost::shared_ptr<Playlist> pl;
4590 vector<boost::shared_ptr<Region> > results;
4592 boost::shared_ptr<Track> tr;
4594 if ((tr = tatv->track()) == 0) {
4599 if ((pl = (tr->playlist())) != 0) {
4600 if (src_comparison) {
4601 pl->get_source_equivalent_regions (region, results);
4603 pl->get_region_list_equivalent_regions (region, results);
4607 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4608 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4609 regions.push_back (marv);
4618 Editor::show_rhythm_ferret ()
4620 if (rhythm_ferret == 0) {
4621 rhythm_ferret = new RhythmFerret(*this);
4624 rhythm_ferret->set_session (_session);
4625 rhythm_ferret->show ();
4626 rhythm_ferret->present ();
4630 Editor::first_idle ()
4632 MessageDialog* dialog = 0;
4634 if (track_views.size() > 1) {
4635 dialog = new MessageDialog (
4637 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4641 ARDOUR_UI::instance()->flush_pending ();
4644 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4648 // first idle adds route children (automation tracks), so we need to redisplay here
4649 _routes->redisplay ();
4656 Editor::_idle_resize (gpointer arg)
4658 return ((Editor*)arg)->idle_resize ();
4662 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4664 if (resize_idle_id < 0) {
4665 resize_idle_id = g_idle_add (_idle_resize, this);
4666 _pending_resize_amount = 0;
4669 /* make a note of the smallest resulting height, so that we can clamp the
4670 lower limit at TimeAxisView::hSmall */
4672 int32_t min_resulting = INT32_MAX;
4674 _pending_resize_amount += h;
4675 _pending_resize_view = view;
4677 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4679 if (selection->tracks.contains (_pending_resize_view)) {
4680 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4681 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4685 if (min_resulting < 0) {
4690 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4691 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4695 /** Handle pending resizing of tracks */
4697 Editor::idle_resize ()
4699 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4701 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4702 selection->tracks.contains (_pending_resize_view)) {
4704 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4705 if (*i != _pending_resize_view) {
4706 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4711 _pending_resize_amount = 0;
4712 _group_tabs->set_dirty ();
4713 resize_idle_id = -1;
4721 ENSURE_GUI_THREAD (*this, &Editor::located);
4724 playhead_cursor->set_position (_session->audible_frame ());
4725 if (_follow_playhead && !_pending_initial_locate) {
4726 reset_x_origin_to_follow_playhead ();
4730 _pending_locate_request = false;
4731 _pending_initial_locate = false;
4735 Editor::region_view_added (RegionView *)
4737 _summary->set_background_dirty ();
4741 Editor::region_view_removed ()
4743 _summary->set_background_dirty ();
4747 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4749 TrackViewList::const_iterator j = track_views.begin ();
4750 while (j != track_views.end()) {
4751 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4752 if (rtv && rtv->route() == r) {
4763 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4767 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4768 TimeAxisView* tv = axis_view_from_route (*i);
4778 Editor::suspend_route_redisplay ()
4781 _routes->suspend_redisplay();
4786 Editor::resume_route_redisplay ()
4789 _routes->resume_redisplay();
4794 Editor::add_routes (RouteList& routes)
4796 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4798 RouteTimeAxisView *rtv;
4799 list<RouteTimeAxisView*> new_views;
4801 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4802 boost::shared_ptr<Route> route = (*x);
4804 if (route->is_auditioner() || route->is_monitor()) {
4808 DataType dt = route->input()->default_type();
4810 if (dt == ARDOUR::DataType::AUDIO) {
4811 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4812 rtv->set_route (route);
4813 } else if (dt == ARDOUR::DataType::MIDI) {
4814 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4815 rtv->set_route (route);
4817 throw unknown_type();
4820 new_views.push_back (rtv);
4821 track_views.push_back (rtv);
4823 rtv->effective_gain_display ();
4825 if (internal_editing()) {
4826 rtv->enter_internal_edit_mode ();
4828 rtv->leave_internal_edit_mode ();
4831 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4832 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4835 if (new_views.size() > 0) {
4836 _routes->routes_added (new_views);
4837 _summary->routes_added (new_views);
4840 if (show_editor_mixer_when_tracks_arrive) {
4841 show_editor_mixer (true);
4844 editor_list_button.set_sensitive (true);
4848 Editor::timeaxisview_deleted (TimeAxisView *tv)
4850 if (tv == entered_track) {
4854 if (_session && _session->deletion_in_progress()) {
4855 /* the situation is under control */
4859 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4861 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4863 _routes->route_removed (tv);
4865 TimeAxisView::Children c = tv->get_child_list ();
4866 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4867 if (entered_track == i->get()) {
4872 /* remove it from the list of track views */
4874 TrackViewList::iterator i;
4876 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4877 i = track_views.erase (i);
4880 /* update whatever the current mixer strip is displaying, if revelant */
4882 boost::shared_ptr<Route> route;
4885 route = rtav->route ();
4888 if (current_mixer_strip && current_mixer_strip->route() == route) {
4890 TimeAxisView* next_tv;
4892 if (track_views.empty()) {
4894 } else if (i == track_views.end()) {
4895 next_tv = track_views.front();
4902 set_selected_mixer_strip (*next_tv);
4904 /* make the editor mixer strip go away setting the
4905 * button to inactive (which also unticks the menu option)
4908 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4914 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4916 if (apply_to_selection) {
4917 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4919 TrackSelection::iterator j = i;
4922 hide_track_in_display (*i, false);
4927 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4929 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4930 // this will hide the mixer strip
4931 set_selected_mixer_strip (*tv);
4934 _routes->hide_track_in_display (*tv);
4939 Editor::sync_track_view_list_and_routes ()
4941 track_views = TrackViewList (_routes->views ());
4943 _summary->set_dirty ();
4944 _group_tabs->set_dirty ();
4946 return false; // do not call again (until needed)
4950 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4952 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4957 /** Find a RouteTimeAxisView by the ID of its route */
4959 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4961 RouteTimeAxisView* v;
4963 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4964 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4965 if(v->route()->id() == id) {
4975 Editor::fit_route_group (RouteGroup *g)
4977 TrackViewList ts = axis_views_from_routes (g->route_list ());
4982 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4984 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4987 _session->cancel_audition ();
4991 if (_session->is_auditioning()) {
4992 _session->cancel_audition ();
4993 if (r == last_audition_region) {
4998 _session->audition_region (r);
4999 last_audition_region = r;
5004 Editor::hide_a_region (boost::shared_ptr<Region> r)
5006 r->set_hidden (true);
5010 Editor::show_a_region (boost::shared_ptr<Region> r)
5012 r->set_hidden (false);
5016 Editor::audition_region_from_region_list ()
5018 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5022 Editor::hide_region_from_region_list ()
5024 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5028 Editor::show_region_in_region_list ()
5030 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5034 Editor::step_edit_status_change (bool yn)
5037 start_step_editing ();
5039 stop_step_editing ();
5044 Editor::start_step_editing ()
5046 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5050 Editor::stop_step_editing ()
5052 step_edit_connection.disconnect ();
5056 Editor::check_step_edit ()
5058 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5059 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5061 mtv->check_step_edit ();
5065 return true; // do it again, till we stop
5069 Editor::scroll_press (Direction dir)
5071 ++_scroll_callbacks;
5073 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5074 /* delay the first auto-repeat */
5080 scroll_backward (1);
5088 scroll_tracks_up_line ();
5092 scroll_tracks_down_line ();
5096 /* do hacky auto-repeat */
5097 if (!_scroll_connection.connected ()) {
5099 _scroll_connection = Glib::signal_timeout().connect (
5100 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5103 _scroll_callbacks = 0;
5110 Editor::scroll_release ()
5112 _scroll_connection.disconnect ();
5115 /** Queue a change for the Editor viewport x origin to follow the playhead */
5117 Editor::reset_x_origin_to_follow_playhead ()
5119 framepos_t const frame = playhead_cursor->current_frame ();
5121 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5123 if (_session->transport_speed() < 0) {
5125 if (frame > (current_page_samples() / 2)) {
5126 center_screen (frame-(current_page_samples()/2));
5128 center_screen (current_page_samples()/2);
5135 if (frame < leftmost_frame) {
5137 if (_session->transport_rolling()) {
5138 /* rolling; end up with the playhead at the right of the page */
5139 l = frame - current_page_samples ();
5141 /* not rolling: end up with the playhead 1/4 of the way along the page */
5142 l = frame - current_page_samples() / 4;
5146 if (_session->transport_rolling()) {
5147 /* rolling: end up with the playhead on the left of the page */
5150 /* not rolling: end up with the playhead 3/4 of the way along the page */
5151 l = frame - 3 * current_page_samples() / 4;
5159 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5165 Editor::super_rapid_screen_update ()
5167 if (!_session || !_session->engine().running()) {
5171 /* METERING / MIXER STRIPS */
5173 /* update track meters, if required */
5174 if (is_mapped() && meters_running) {
5175 RouteTimeAxisView* rtv;
5176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5177 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5178 rtv->fast_update ();
5183 /* and any current mixer strip */
5184 if (current_mixer_strip) {
5185 current_mixer_strip->fast_update ();
5188 /* PLAYHEAD AND VIEWPORT */
5190 framepos_t const frame = _session->audible_frame();
5192 /* There are a few reasons why we might not update the playhead / viewport stuff:
5194 * 1. we don't update things when there's a pending locate request, otherwise
5195 * when the editor requests a locate there is a chance that this method
5196 * will move the playhead before the locate request is processed, causing
5198 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5199 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5202 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5204 last_update_frame = frame;
5206 if (!_dragging_playhead) {
5207 playhead_cursor->set_position (frame);
5210 if (!_stationary_playhead) {
5212 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5213 /* We only do this if we aren't already
5214 handling a visual change (ie if
5215 pending_visual_change.being_handled is
5216 false) so that these requests don't stack
5217 up there are too many of them to handle in
5220 reset_x_origin_to_follow_playhead ();
5225 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5229 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5230 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5231 if (target <= 0.0) {
5234 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5235 target = (target * 0.15) + (current * 0.85);
5241 set_horizontal_position (current);
5250 Editor::session_going_away ()
5252 _have_idled = false;
5254 _session_connections.drop_connections ();
5256 super_rapid_screen_update_connection.disconnect ();
5258 selection->clear ();
5259 cut_buffer->clear ();
5261 clicked_regionview = 0;
5262 clicked_axisview = 0;
5263 clicked_routeview = 0;
5264 entered_regionview = 0;
5266 last_update_frame = 0;
5269 playhead_cursor->hide ();
5271 /* rip everything out of the list displays */
5275 _route_groups->clear ();
5277 /* do this first so that deleting a track doesn't reset cms to null
5278 and thus cause a leak.
5281 if (current_mixer_strip) {
5282 if (current_mixer_strip->get_parent() != 0) {
5283 global_hpacker.remove (*current_mixer_strip);
5285 delete current_mixer_strip;
5286 current_mixer_strip = 0;
5289 /* delete all trackviews */
5291 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5294 track_views.clear ();
5296 nudge_clock->set_session (0);
5298 editor_list_button.set_active(false);
5299 editor_list_button.set_sensitive(false);
5301 /* clear tempo/meter rulers */
5302 remove_metric_marks ();
5304 clear_marker_display ();
5306 stop_step_editing ();
5308 /* get rid of any existing editor mixer strip */
5310 WindowTitle title(Glib::get_application_name());
5311 title += _("Editor");
5313 set_title (title.get_string());
5315 SessionHandlePtr::session_going_away ();
5320 Editor::show_editor_list (bool yn)
5323 _the_notebook.show ();
5325 _the_notebook.hide ();
5330 Editor::change_region_layering_order (bool from_context_menu)
5332 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5334 if (!clicked_routeview) {
5335 if (layering_order_editor) {
5336 layering_order_editor->hide ();
5341 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5347 boost::shared_ptr<Playlist> pl = track->playlist();
5353 if (layering_order_editor == 0) {
5354 layering_order_editor = new RegionLayeringOrderEditor (*this);
5357 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5358 layering_order_editor->maybe_present ();
5362 Editor::update_region_layering_order_editor ()
5364 if (layering_order_editor && layering_order_editor->is_visible ()) {
5365 change_region_layering_order (true);
5370 Editor::setup_fade_images ()
5372 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5373 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5374 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5375 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5376 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5378 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5379 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5380 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5381 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5382 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5384 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5385 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5386 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5387 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5388 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5390 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5391 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5392 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5393 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5394 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5398 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5400 Editor::action_menu_item (std::string const & name)
5402 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5405 return *manage (a->create_menu_item ());
5409 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5411 EventBox* b = manage (new EventBox);
5412 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5413 Label* l = manage (new Label (name));
5417 _the_notebook.append_page (widget, *b);
5421 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5423 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5424 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5427 if (ev->type == GDK_2BUTTON_PRESS) {
5429 /* double-click on a notebook tab shrinks or expands the notebook */
5431 if (_notebook_shrunk) {
5432 if (pre_notebook_shrink_pane_width) {
5433 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5435 _notebook_shrunk = false;
5437 pre_notebook_shrink_pane_width = edit_pane.get_position();
5439 /* this expands the LHS of the edit pane to cover the notebook
5440 PAGE but leaves the tabs visible.
5442 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5443 _notebook_shrunk = true;
5451 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5453 using namespace Menu_Helpers;
5455 MenuList& items = _control_point_context_menu.items ();
5458 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5459 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5460 if (!can_remove_control_point (item)) {
5461 items.back().set_sensitive (false);
5464 _control_point_context_menu.popup (event->button.button, event->button.time);
5468 Editor::zoom_vertical_modifier_released()
5470 _stepping_axis_view = 0;
5474 Editor::ui_parameter_changed (string parameter)
5476 if (parameter == "icon-set") {
5477 while (!_cursor_stack.empty()) {
5478 _cursor_stack.pop();
5480 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5481 } else if (parameter == "draggable-playhead") {
5482 if (_verbose_cursor) {
5483 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());