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[] = {
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 (*hbox, true, true);
622 global_hpacker.pack_start (global_vpacker, true, true);
624 set_name ("EditorWindow");
625 add_accel_group (ActionManager::ui_manager->get_accel_group());
627 status_bar_hpacker.show ();
629 vpacker.pack_end (status_bar_hpacker, false, false);
630 vpacker.pack_end (global_hpacker, true, true);
631 vpacker.pack_end (top_hbox, false, false);
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 _ignore_follow_edits = false;
749 _show_marker_lines = false;
751 /* Button bindings */
753 button_bindings = new Bindings;
755 XMLNode* node = button_settings();
757 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
758 button_bindings->load (**i);
764 /* grab current parameter state */
765 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
766 ARDOUR_UI::config()->map_parameters (pc);
768 setup_fade_images ();
775 delete button_bindings;
777 delete _route_groups;
778 delete _track_canvas_viewport;
783 Editor::button_settings () const
785 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
786 XMLNode* node = find_named_node (*settings, X_("Buttons"));
789 node = new XMLNode (X_("Buttons"));
796 Editor::add_toplevel_controls (Container& cont)
798 vpacker.pack_start (cont, false, false);
803 Editor::get_smart_mode () const
805 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
809 Editor::catch_vanishing_regionview (RegionView *rv)
811 /* note: the selection will take care of the vanishing
812 audioregionview by itself.
815 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
819 if (clicked_regionview == rv) {
820 clicked_regionview = 0;
823 if (entered_regionview == rv) {
824 set_entered_regionview (0);
827 if (!_all_region_actions_sensitized) {
828 sensitize_all_region_actions (true);
833 Editor::set_entered_regionview (RegionView* rv)
835 if (rv == entered_regionview) {
839 if (entered_regionview) {
840 entered_regionview->exited ();
843 entered_regionview = rv;
845 if (entered_regionview != 0) {
846 entered_regionview->entered (internal_editing ());
849 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
850 /* This RegionView entry might have changed what region actions
851 are allowed, so sensitize them all in case a key is pressed.
853 sensitize_all_region_actions (true);
858 Editor::set_entered_track (TimeAxisView* tav)
861 entered_track->exited ();
867 entered_track->entered ();
872 Editor::show_window ()
874 if (!is_visible ()) {
877 /* XXX: this is a bit unfortunate; it would probably
878 be nicer if we could just call show () above rather
879 than needing the show_all ()
882 /* re-hide stuff if necessary */
883 editor_list_button_toggled ();
884 parameter_changed ("show-summary");
885 parameter_changed ("show-group-tabs");
886 parameter_changed ("show-zoom-tools");
888 /* now reset all audio_time_axis heights, because widgets might need
894 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
895 tv = (static_cast<TimeAxisView*>(*i));
899 if (current_mixer_strip) {
900 current_mixer_strip->hide_things ();
901 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
909 Editor::instant_save ()
911 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
916 _session->add_instant_xml(get_state());
918 Config->add_instant_xml(get_state());
923 Editor::control_vertical_zoom_in_all ()
925 tav_zoom_smooth (false, true);
929 Editor::control_vertical_zoom_out_all ()
931 tav_zoom_smooth (true, true);
935 Editor::control_vertical_zoom_in_selected ()
937 tav_zoom_smooth (false, false);
941 Editor::control_vertical_zoom_out_selected ()
943 tav_zoom_smooth (true, false);
947 Editor::control_view (uint32_t view)
949 goto_visual_state (view);
953 Editor::control_unselect ()
955 selection->clear_tracks ();
959 Editor::control_select (uint32_t rid, Selection::Operation op)
961 /* handles the (static) signal from the ControlProtocol class that
962 * requests setting the selected track to a given RID
969 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
975 TimeAxisView* tav = axis_view_from_route (r);
980 selection->add (tav);
982 case Selection::Toggle:
983 selection->toggle (tav);
985 case Selection::Extend:
988 selection->set (tav);
992 selection->clear_tracks ();
997 Editor::control_step_tracks_up ()
999 scroll_tracks_up_line ();
1003 Editor::control_step_tracks_down ()
1005 scroll_tracks_down_line ();
1009 Editor::control_scroll (float fraction)
1011 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1017 double step = fraction * current_page_samples();
1020 _control_scroll_target is an optional<T>
1022 it acts like a pointer to an framepos_t, with
1023 a operator conversion to boolean to check
1024 that it has a value could possibly use
1025 playhead_cursor->current_frame to store the
1026 value and a boolean in the class to know
1027 when it's out of date
1030 if (!_control_scroll_target) {
1031 _control_scroll_target = _session->transport_frame();
1032 _dragging_playhead = true;
1035 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1036 *_control_scroll_target = 0;
1037 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1038 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1040 *_control_scroll_target += (framepos_t) floor (step);
1043 /* move visuals, we'll catch up with it later */
1045 playhead_cursor->set_position (*_control_scroll_target);
1046 UpdateAllTransportClocks (*_control_scroll_target);
1048 if (*_control_scroll_target > (current_page_samples() / 2)) {
1049 /* try to center PH in window */
1050 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1056 Now we do a timeout to actually bring the session to the right place
1057 according to the playhead. This is to avoid reading disk buffers on every
1058 call to control_scroll, which is driven by ScrollTimeline and therefore
1059 probably by a control surface wheel which can generate lots of events.
1061 /* cancel the existing timeout */
1063 control_scroll_connection.disconnect ();
1065 /* add the next timeout */
1067 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1071 Editor::deferred_control_scroll (framepos_t /*target*/)
1073 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1074 // reset for next stream
1075 _control_scroll_target = boost::none;
1076 _dragging_playhead = false;
1081 Editor::access_action (std::string action_group, std::string action_item)
1087 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1090 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1098 Editor::on_realize ()
1100 Window::on_realize ();
1103 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1104 start_lock_event_timing ();
1107 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1111 Editor::start_lock_event_timing ()
1113 /* check if we should lock the GUI every 30 seconds */
1115 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1119 Editor::generic_event_handler (GdkEvent* ev)
1122 case GDK_BUTTON_PRESS:
1123 case GDK_BUTTON_RELEASE:
1124 case GDK_MOTION_NOTIFY:
1126 case GDK_KEY_RELEASE:
1127 gettimeofday (&last_event_time, 0);
1136 Editor::lock_timeout_callback ()
1138 struct timeval now, delta;
1140 gettimeofday (&now, 0);
1142 timersub (&now, &last_event_time, &delta);
1144 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1146 /* don't call again. Returning false will effectively
1147 disconnect us from the timer callback.
1149 unlock() will call start_lock_event_timing() to get things
1159 Editor::map_position_change (framepos_t frame)
1161 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1163 if (_session == 0) {
1167 if (_follow_playhead) {
1168 center_screen (frame);
1171 playhead_cursor->set_position (frame);
1175 Editor::center_screen (framepos_t frame)
1177 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1179 /* if we're off the page, then scroll.
1182 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1183 center_screen_internal (frame, page);
1188 Editor::center_screen_internal (framepos_t frame, float page)
1193 frame -= (framepos_t) page;
1198 reset_x_origin (frame);
1203 Editor::update_title ()
1205 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1208 bool dirty = _session->dirty();
1210 string session_name;
1212 if (_session->snap_name() != _session->name()) {
1213 session_name = _session->snap_name();
1215 session_name = _session->name();
1219 session_name = "*" + session_name;
1222 WindowTitle title(session_name);
1223 title += Glib::get_application_name();
1224 set_title (title.get_string());
1226 /* ::session_going_away() will have taken care of it */
1231 Editor::set_session (Session *t)
1233 SessionHandlePtr::set_session (t);
1239 _playlist_selector->set_session (_session);
1240 nudge_clock->set_session (_session);
1241 _summary->set_session (_session);
1242 _group_tabs->set_session (_session);
1243 _route_groups->set_session (_session);
1244 _regions->set_session (_session);
1245 _snapshots->set_session (_session);
1246 _routes->set_session (_session);
1247 _locations->set_session (_session);
1249 if (rhythm_ferret) {
1250 rhythm_ferret->set_session (_session);
1253 if (analysis_window) {
1254 analysis_window->set_session (_session);
1258 sfbrowser->set_session (_session);
1261 compute_fixed_ruler_scale ();
1263 /* Make sure we have auto loop and auto punch ranges */
1265 Location* loc = _session->locations()->auto_loop_location();
1267 loc->set_name (_("Loop"));
1270 loc = _session->locations()->auto_punch_location();
1273 loc->set_name (_("Punch"));
1276 refresh_location_display ();
1278 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1279 the selected Marker; this needs the LocationMarker list to be available.
1281 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1282 set_state (*node, Stateful::loading_state_version);
1284 /* catch up with the playhead */
1286 _session->request_locate (playhead_cursor->current_frame ());
1287 _pending_initial_locate = true;
1291 /* These signals can all be emitted by a non-GUI thread. Therefore the
1292 handlers for them must not attempt to directly interact with the GUI,
1293 but use PBD::Signal<T>::connect() which accepts an event loop
1294 ("context") where the handler will be asked to run.
1297 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1298 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1299 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1300 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1301 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1302 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1303 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1304 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1305 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1306 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1307 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1308 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1309 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1310 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1312 playhead_cursor->show ();
1314 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1315 Config->map_parameters (pc);
1316 _session->config.map_parameters (pc);
1318 restore_ruler_visibility ();
1319 //tempo_map_changed (PropertyChange (0));
1320 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1322 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1323 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1326 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1327 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1330 switch (_snap_type) {
1331 case SnapToRegionStart:
1332 case SnapToRegionEnd:
1333 case SnapToRegionSync:
1334 case SnapToRegionBoundary:
1335 build_region_boundary_cache ();
1342 /* register for undo history */
1343 _session->register_with_memento_command_factory(id(), this);
1345 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1347 start_updating_meters ();
1351 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1353 if (a->get_name() == "RegionMenu") {
1354 /* When the main menu's region menu is opened, we setup the actions so that they look right
1355 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1356 so we resensitize all region actions when the entered regionview or the region selection
1357 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1358 happens after the region context menu is opened. So we set a flag here, too.
1362 sensitize_the_right_region_actions ();
1363 _last_region_menu_was_main = true;
1368 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1370 using namespace Menu_Helpers;
1372 void (Editor::*emf)(FadeShape);
1373 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1376 images = &_xfade_in_images;
1377 emf = &Editor::set_fade_in_shape;
1379 images = &_xfade_out_images;
1380 emf = &Editor::set_fade_out_shape;
1385 _("Linear (for highly correlated material)"),
1386 *(*images)[FadeLinear],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1391 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 _("Constant power"),
1396 *(*images)[FadeConstantPower],
1397 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1405 *(*images)[FadeSymmetric],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1410 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1415 *(*images)[FadeSlow],
1416 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1424 *(*images)[FadeFast],
1425 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1428 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1431 /** Pop up a context menu for when the user clicks on a start crossfade */
1433 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1435 using namespace Menu_Helpers;
1436 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1439 MenuList& items (xfade_in_context_menu.items());
1442 if (arv->audio_region()->fade_in_active()) {
1443 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1445 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1448 items.push_back (SeparatorElem());
1449 fill_xfade_menu (items, true);
1451 xfade_in_context_menu.popup (button, time);
1454 /** Pop up a context menu for when the user clicks on an end crossfade */
1456 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1458 using namespace Menu_Helpers;
1459 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1462 MenuList& items (xfade_out_context_menu.items());
1465 if (arv->audio_region()->fade_out_active()) {
1466 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1468 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1471 items.push_back (SeparatorElem());
1472 fill_xfade_menu (items, false);
1474 xfade_out_context_menu.popup (button, time);
1478 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1480 using namespace Menu_Helpers;
1481 Menu* (Editor::*build_menu_function)();
1484 switch (item_type) {
1486 case RegionViewName:
1487 case RegionViewNameHighlight:
1488 case LeftFrameHandle:
1489 case RightFrameHandle:
1490 if (with_selection) {
1491 build_menu_function = &Editor::build_track_selection_context_menu;
1493 build_menu_function = &Editor::build_track_region_context_menu;
1498 if (with_selection) {
1499 build_menu_function = &Editor::build_track_selection_context_menu;
1501 build_menu_function = &Editor::build_track_context_menu;
1506 if (clicked_routeview->track()) {
1507 build_menu_function = &Editor::build_track_context_menu;
1509 build_menu_function = &Editor::build_track_bus_context_menu;
1514 /* probably shouldn't happen but if it does, we don't care */
1518 menu = (this->*build_menu_function)();
1519 menu->set_name ("ArdourContextMenu");
1521 /* now handle specific situations */
1523 switch (item_type) {
1525 case RegionViewName:
1526 case RegionViewNameHighlight:
1527 case LeftFrameHandle:
1528 case RightFrameHandle:
1529 if (!with_selection) {
1530 if (region_edit_menu_split_item) {
1531 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1532 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1534 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1537 if (region_edit_menu_split_multichannel_item) {
1538 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1539 region_edit_menu_split_multichannel_item->set_sensitive (true);
1541 region_edit_menu_split_multichannel_item->set_sensitive (false);
1554 /* probably shouldn't happen but if it does, we don't care */
1558 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1560 /* Bounce to disk */
1562 using namespace Menu_Helpers;
1563 MenuList& edit_items = menu->items();
1565 edit_items.push_back (SeparatorElem());
1567 switch (clicked_routeview->audio_track()->freeze_state()) {
1568 case AudioTrack::NoFreeze:
1569 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1572 case AudioTrack::Frozen:
1573 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1576 case AudioTrack::UnFrozen:
1577 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1583 if (item_type == StreamItem && clicked_routeview) {
1584 clicked_routeview->build_underlay_menu(menu);
1587 /* When the region menu is opened, we setup the actions so that they look right
1590 sensitize_the_right_region_actions ();
1591 _last_region_menu_was_main = false;
1593 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1594 menu->popup (button, time);
1598 Editor::build_track_context_menu ()
1600 using namespace Menu_Helpers;
1602 MenuList& edit_items = track_context_menu.items();
1605 add_dstream_context_items (edit_items);
1606 return &track_context_menu;
1610 Editor::build_track_bus_context_menu ()
1612 using namespace Menu_Helpers;
1614 MenuList& edit_items = track_context_menu.items();
1617 add_bus_context_items (edit_items);
1618 return &track_context_menu;
1622 Editor::build_track_region_context_menu ()
1624 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_region_context_menu.items();
1628 /* we've just cleared the track region context menu, so the menu that these
1629 two items were on will have disappeared; stop them dangling.
1631 region_edit_menu_split_item = 0;
1632 region_edit_menu_split_multichannel_item = 0;
1634 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1637 boost::shared_ptr<Track> tr;
1638 boost::shared_ptr<Playlist> pl;
1640 if ((tr = rtv->track())) {
1641 add_region_context_items (edit_items, tr);
1645 add_dstream_context_items (edit_items);
1647 return &track_region_context_menu;
1651 Editor::analyze_region_selection ()
1653 if (analysis_window == 0) {
1654 analysis_window = new AnalysisWindow();
1657 analysis_window->set_session(_session);
1659 analysis_window->show_all();
1662 analysis_window->set_regionmode();
1663 analysis_window->analyze();
1665 analysis_window->present();
1669 Editor::analyze_range_selection()
1671 if (analysis_window == 0) {
1672 analysis_window = new AnalysisWindow();
1675 analysis_window->set_session(_session);
1677 analysis_window->show_all();
1680 analysis_window->set_rangemode();
1681 analysis_window->analyze();
1683 analysis_window->present();
1687 Editor::build_track_selection_context_menu ()
1689 using namespace Menu_Helpers;
1690 MenuList& edit_items = track_selection_context_menu.items();
1691 edit_items.clear ();
1693 add_selection_context_items (edit_items);
1694 // edit_items.push_back (SeparatorElem());
1695 // add_dstream_context_items (edit_items);
1697 return &track_selection_context_menu;
1701 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1703 using namespace Menu_Helpers;
1705 /* OK, stick the region submenu at the top of the list, and then add
1709 RegionSelection rs = get_regions_from_selection_and_entered ();
1711 string::size_type pos = 0;
1712 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1714 /* we have to hack up the region name because "_" has a special
1715 meaning for menu titles.
1718 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1719 menu_item_name.replace (pos, 1, "__");
1723 if (_popup_region_menu_item == 0) {
1724 _popup_region_menu_item = new MenuItem (menu_item_name);
1725 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1726 _popup_region_menu_item->show ();
1728 _popup_region_menu_item->set_label (menu_item_name);
1731 const framepos_t position = get_preferred_edit_position (false, true);
1733 edit_items.push_back (*_popup_region_menu_item);
1734 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1735 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1737 edit_items.push_back (SeparatorElem());
1740 /** Add context menu items relevant to selection ranges.
1741 * @param edit_items List to add the items to.
1744 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1746 using namespace Menu_Helpers;
1748 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1749 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1751 edit_items.push_back (SeparatorElem());
1752 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1754 edit_items.push_back (SeparatorElem());
1756 edit_items.push_back (
1758 _("Move Range Start to Previous Region Boundary"),
1759 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1763 edit_items.push_back (
1765 _("Move Range Start to Next Region Boundary"),
1766 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1770 edit_items.push_back (
1772 _("Move Range End to Previous Region Boundary"),
1773 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1777 edit_items.push_back (
1779 _("Move Range End to Next Region Boundary"),
1780 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1784 edit_items.push_back (SeparatorElem());
1785 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1786 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1788 edit_items.push_back (SeparatorElem());
1789 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1791 edit_items.push_back (SeparatorElem());
1792 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1793 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1795 edit_items.push_back (SeparatorElem());
1796 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1798 edit_items.push_back (SeparatorElem());
1799 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1800 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1801 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1805 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1806 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1807 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1808 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1809 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1810 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1816 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1818 using namespace Menu_Helpers;
1822 Menu *play_menu = manage (new Menu);
1823 MenuList& play_items = play_menu->items();
1824 play_menu->set_name ("ArdourContextMenu");
1826 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1827 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1828 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1829 play_items.push_back (SeparatorElem());
1830 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1832 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1836 Menu *select_menu = manage (new Menu);
1837 MenuList& select_items = select_menu->items();
1838 select_menu->set_name ("ArdourContextMenu");
1840 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1841 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1842 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1843 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1844 select_items.push_back (SeparatorElem());
1845 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1846 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1847 select_items.push_back (SeparatorElem());
1848 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1849 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1850 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1851 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1852 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1853 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1854 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1856 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1860 Menu *cutnpaste_menu = manage (new Menu);
1861 MenuList& cutnpaste_items = cutnpaste_menu->items();
1862 cutnpaste_menu->set_name ("ArdourContextMenu");
1864 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1865 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1866 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1868 cutnpaste_items.push_back (SeparatorElem());
1870 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1871 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1873 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1875 /* Adding new material */
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1879 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1883 Menu *nudge_menu = manage (new Menu());
1884 MenuList& nudge_items = nudge_menu->items();
1885 nudge_menu->set_name ("ArdourContextMenu");
1887 edit_items.push_back (SeparatorElem());
1888 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1889 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1890 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1891 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1893 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1897 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1899 using namespace Menu_Helpers;
1903 Menu *play_menu = manage (new Menu);
1904 MenuList& play_items = play_menu->items();
1905 play_menu->set_name ("ArdourContextMenu");
1907 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1908 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1909 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1913 Menu *select_menu = manage (new Menu);
1914 MenuList& select_items = select_menu->items();
1915 select_menu->set_name ("ArdourContextMenu");
1917 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1918 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1919 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1920 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1921 select_items.push_back (SeparatorElem());
1922 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1923 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1924 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1925 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1927 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1931 Menu *cutnpaste_menu = manage (new Menu);
1932 MenuList& cutnpaste_items = cutnpaste_menu->items();
1933 cutnpaste_menu->set_name ("ArdourContextMenu");
1935 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1936 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1937 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1939 Menu *nudge_menu = manage (new Menu());
1940 MenuList& nudge_items = nudge_menu->items();
1941 nudge_menu->set_name ("ArdourContextMenu");
1943 edit_items.push_back (SeparatorElem());
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1946 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1947 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1949 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1953 Editor::snap_type() const
1959 Editor::snap_mode() const
1965 Editor::set_snap_to (SnapType st)
1967 unsigned int snap_ind = (unsigned int)st;
1971 if (snap_ind > snap_type_strings.size() - 1) {
1973 _snap_type = (SnapType)snap_ind;
1976 string str = snap_type_strings[snap_ind];
1978 if (str != snap_type_selector.get_text()) {
1979 snap_type_selector.set_text (str);
1984 switch (_snap_type) {
1985 case SnapToBeatDiv128:
1986 case SnapToBeatDiv64:
1987 case SnapToBeatDiv32:
1988 case SnapToBeatDiv28:
1989 case SnapToBeatDiv24:
1990 case SnapToBeatDiv20:
1991 case SnapToBeatDiv16:
1992 case SnapToBeatDiv14:
1993 case SnapToBeatDiv12:
1994 case SnapToBeatDiv10:
1995 case SnapToBeatDiv8:
1996 case SnapToBeatDiv7:
1997 case SnapToBeatDiv6:
1998 case SnapToBeatDiv5:
1999 case SnapToBeatDiv4:
2000 case SnapToBeatDiv3:
2001 case SnapToBeatDiv2: {
2002 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2003 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2005 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2006 current_bbt_points_begin, current_bbt_points_end);
2007 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2008 current_bbt_points_begin, current_bbt_points_end);
2009 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2013 case SnapToRegionStart:
2014 case SnapToRegionEnd:
2015 case SnapToRegionSync:
2016 case SnapToRegionBoundary:
2017 build_region_boundary_cache ();
2025 SnapChanged (); /* EMIT SIGNAL */
2029 Editor::set_snap_mode (SnapMode mode)
2031 string str = snap_mode_strings[(int)mode];
2033 if (_internal_editing) {
2034 internal_snap_mode = mode;
2036 pre_internal_snap_mode = mode;
2041 if (str != snap_mode_selector.get_text ()) {
2042 snap_mode_selector.set_text (str);
2048 Editor::set_edit_point_preference (EditPoint ep, bool force)
2050 bool changed = (_edit_point != ep);
2053 string str = edit_point_strings[(int)ep];
2055 if (str != edit_point_selector.get_text ()) {
2056 edit_point_selector.set_text (str);
2059 reset_canvas_cursor ();
2061 if (!force && !changed) {
2065 const char* action=NULL;
2067 switch (_edit_point) {
2068 case EditAtPlayhead:
2069 action = "edit-at-playhead";
2071 case EditAtSelectedMarker:
2072 action = "edit-at-marker";
2075 action = "edit-at-mouse";
2079 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2081 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2085 bool in_track_canvas;
2087 if (!mouse_frame (foo, in_track_canvas)) {
2088 in_track_canvas = false;
2091 reset_canvas_action_sensitivity (in_track_canvas);
2097 Editor::set_state (const XMLNode& node, int /*version*/)
2099 const XMLProperty* prop;
2106 g.base_width = default_width;
2107 g.base_height = default_height;
2111 if ((geometry = find_named_node (node, "geometry")) != 0) {
2115 if ((prop = geometry->property("x_size")) == 0) {
2116 prop = geometry->property ("x-size");
2119 g.base_width = atoi(prop->value());
2121 if ((prop = geometry->property("y_size")) == 0) {
2122 prop = geometry->property ("y-size");
2125 g.base_height = atoi(prop->value());
2128 if ((prop = geometry->property ("x_pos")) == 0) {
2129 prop = geometry->property ("x-pos");
2132 x = atoi (prop->value());
2135 if ((prop = geometry->property ("y_pos")) == 0) {
2136 prop = geometry->property ("y-pos");
2139 y = atoi (prop->value());
2143 set_default_size (g.base_width, g.base_height);
2146 if (_session && (prop = node.property ("playhead"))) {
2148 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2149 playhead_cursor->set_position (pos);
2151 playhead_cursor->set_position (0);
2154 if ((prop = node.property ("mixer-width"))) {
2155 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2158 if ((prop = node.property ("zoom-focus"))) {
2159 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2162 if ((prop = node.property ("zoom"))) {
2163 /* older versions of ardour used floating point samples_per_pixel */
2164 double f = PBD::atof (prop->value());
2165 reset_zoom (llrintf (f));
2167 reset_zoom (samples_per_pixel);
2170 if ((prop = node.property ("visible-track-count"))) {
2171 set_visible_track_count (PBD::atoi (prop->value()));
2174 if ((prop = node.property ("snap-to"))) {
2175 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2178 if ((prop = node.property ("snap-mode"))) {
2179 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2182 if ((prop = node.property ("internal-snap-to"))) {
2183 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2186 if ((prop = node.property ("internal-snap-mode"))) {
2187 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2190 if ((prop = node.property ("pre-internal-snap-to"))) {
2191 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2195 if ((prop = node.property ("pre-internal-snap-mode"))) {
2196 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2199 if ((prop = node.property ("mouse-mode"))) {
2200 MouseMode m = str2mousemode(prop->value());
2201 set_mouse_mode (m, true);
2203 set_mouse_mode (MouseObject, true);
2206 if ((prop = node.property ("left-frame")) != 0) {
2208 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2212 reset_x_origin (pos);
2216 if ((prop = node.property ("y-origin")) != 0) {
2217 reset_y_origin (atof (prop->value ()));
2220 if ((prop = node.property ("internal-edit"))) {
2221 bool yn = string_is_affirmative (prop->value());
2222 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2224 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2225 tact->set_active (!yn);
2226 tact->set_active (yn);
2230 if ((prop = node.property ("join-object-range"))) {
2231 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2232 bool yn = string_is_affirmative (prop->value());
2234 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2235 tact->set_active (!yn);
2236 tact->set_active (yn);
2238 set_mouse_mode(mouse_mode, true);
2241 if ((prop = node.property ("edit-point"))) {
2242 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2245 if ((prop = node.property ("show-measures"))) {
2246 bool yn = string_is_affirmative (prop->value());
2247 _show_measures = yn;
2248 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2250 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2251 /* do it twice to force the change */
2252 tact->set_active (!yn);
2253 tact->set_active (yn);
2257 if ((prop = node.property ("follow-playhead"))) {
2258 bool yn = string_is_affirmative (prop->value());
2259 set_follow_playhead (yn);
2260 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2262 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2263 if (tact->get_active() != yn) {
2264 tact->set_active (yn);
2269 if ((prop = node.property ("stationary-playhead"))) {
2270 bool yn = string_is_affirmative (prop->value());
2271 set_stationary_playhead (yn);
2272 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2274 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2275 if (tact->get_active() != yn) {
2276 tact->set_active (yn);
2281 if ((prop = node.property ("region-list-sort-type"))) {
2282 RegionListSortType st;
2283 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2286 if ((prop = node.property ("show-editor-mixer"))) {
2288 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2291 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2292 bool yn = string_is_affirmative (prop->value());
2294 /* do it twice to force the change */
2296 tact->set_active (!yn);
2297 tact->set_active (yn);
2300 if ((prop = node.property ("show-editor-list"))) {
2302 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2305 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2306 bool yn = string_is_affirmative (prop->value());
2308 /* do it twice to force the change */
2310 tact->set_active (!yn);
2311 tact->set_active (yn);
2314 if ((prop = node.property (X_("editor-list-page")))) {
2315 _the_notebook.set_current_page (atoi (prop->value ()));
2318 if ((prop = node.property (X_("show-marker-lines")))) {
2319 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2321 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2322 bool yn = string_is_affirmative (prop->value ());
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2328 XMLNodeList children = node.children ();
2329 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2330 selection->set_state (**i, Stateful::current_state_version);
2331 _regions->set_state (**i);
2334 if ((prop = node.property ("maximised"))) {
2335 bool yn = string_is_affirmative (prop->value());
2336 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2338 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2339 bool fs = tact && tact->get_active();
2341 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2345 if ((prop = node.property ("nudge-clock-value"))) {
2347 sscanf (prop->value().c_str(), "%" PRId64, &f);
2348 nudge_clock->set (f);
2350 nudge_clock->set_mode (AudioClock::Timecode);
2351 nudge_clock->set (_session->frame_rate() * 5, true);
2358 Editor::get_state ()
2360 XMLNode* node = new XMLNode ("Editor");
2363 id().print (buf, sizeof (buf));
2364 node->add_property ("id", buf);
2366 if (is_realized()) {
2367 Glib::RefPtr<Gdk::Window> win = get_window();
2369 int x, y, width, height;
2370 win->get_root_origin(x, y);
2371 win->get_size(width, height);
2373 XMLNode* geometry = new XMLNode ("geometry");
2375 snprintf(buf, sizeof(buf), "%d", width);
2376 geometry->add_property("x-size", string(buf));
2377 snprintf(buf, sizeof(buf), "%d", height);
2378 geometry->add_property("y-size", string(buf));
2379 snprintf(buf, sizeof(buf), "%d", x);
2380 geometry->add_property("x-pos", string(buf));
2381 snprintf(buf, sizeof(buf), "%d", y);
2382 geometry->add_property("y-pos", string(buf));
2383 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2384 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2385 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2386 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2387 geometry->add_property("edit-vertical-pane-pos", string(buf));
2389 node->add_child_nocopy (*geometry);
2392 maybe_add_mixer_strip_width (*node);
2394 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2396 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2397 node->add_property ("zoom", buf);
2398 node->add_property ("snap-to", enum_2_string (_snap_type));
2399 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2400 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2401 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2402 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2403 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2404 node->add_property ("edit-point", enum_2_string (_edit_point));
2405 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2406 node->add_property ("visible-track-count", buf);
2408 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2409 node->add_property ("playhead", buf);
2410 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2411 node->add_property ("left-frame", buf);
2412 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2413 node->add_property ("y-origin", buf);
2415 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2416 node->add_property ("maximised", _maximised ? "yes" : "no");
2417 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2418 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2419 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2420 node->add_property ("mouse-mode", enum2str(mouse_mode));
2421 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2422 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2424 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2426 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2427 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2430 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2432 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2433 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2436 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2437 node->add_property (X_("editor-list-page"), buf);
2439 if (button_bindings) {
2440 XMLNode* bb = new XMLNode (X_("Buttons"));
2441 button_bindings->save (*bb);
2442 node->add_child_nocopy (*bb);
2445 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2447 node->add_child_nocopy (selection->get_state ());
2448 node->add_child_nocopy (_regions->get_state ());
2450 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2451 node->add_property ("nudge-clock-value", buf);
2456 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2457 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2459 * @return pair: TimeAxisView that y is over, layer index.
2461 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2462 * in stacked or expanded region display mode, otherwise 0.
2464 std::pair<TimeAxisView *, double>
2465 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2467 if (!trackview_relative_offset) {
2468 y -= _trackview_group->canvas_origin().y;
2472 return std::make_pair ( (TimeAxisView *) 0, 0);
2475 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2477 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2484 return std::make_pair ( (TimeAxisView *) 0, 0);
2487 /** Snap a position to the grid, if appropriate, taking into account current
2488 * grid settings and also the state of any snap modifier keys that may be pressed.
2489 * @param start Position to snap.
2490 * @param event Event to get current key modifier information from, or 0.
2493 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2495 if (!_session || !event) {
2499 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2500 if (_snap_mode == SnapOff) {
2501 snap_to_internal (start, direction, for_mark);
2504 if (_snap_mode != SnapOff) {
2505 snap_to_internal (start, direction, for_mark);
2511 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2513 if (!_session || _snap_mode == SnapOff) {
2517 snap_to_internal (start, direction, for_mark);
2521 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2523 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2524 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2526 switch (_snap_type) {
2527 case SnapToTimecodeFrame:
2528 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2529 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2531 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2535 case SnapToTimecodeSeconds:
2536 if (_session->config.get_timecode_offset_negative()) {
2537 start += _session->config.get_timecode_offset ();
2539 start -= _session->config.get_timecode_offset ();
2541 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2542 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2544 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2547 if (_session->config.get_timecode_offset_negative()) {
2548 start -= _session->config.get_timecode_offset ();
2550 start += _session->config.get_timecode_offset ();
2554 case SnapToTimecodeMinutes:
2555 if (_session->config.get_timecode_offset_negative()) {
2556 start += _session->config.get_timecode_offset ();
2558 start -= _session->config.get_timecode_offset ();
2560 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2561 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2563 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2565 if (_session->config.get_timecode_offset_negative()) {
2566 start -= _session->config.get_timecode_offset ();
2568 start += _session->config.get_timecode_offset ();
2572 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2578 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2580 const framepos_t one_second = _session->frame_rate();
2581 const framepos_t one_minute = _session->frame_rate() * 60;
2582 framepos_t presnap = start;
2586 switch (_snap_type) {
2587 case SnapToTimecodeFrame:
2588 case SnapToTimecodeSeconds:
2589 case SnapToTimecodeMinutes:
2590 return timecode_snap_to_internal (start, direction, for_mark);
2593 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2594 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2596 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2601 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2602 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2604 start = (framepos_t) floor ((double) start / one_second) * one_second;
2609 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2610 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2612 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2617 start = _session->tempo_map().round_to_bar (start, direction);
2621 start = _session->tempo_map().round_to_beat (start, direction);
2624 case SnapToBeatDiv128:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2627 case SnapToBeatDiv64:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2630 case SnapToBeatDiv32:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2633 case SnapToBeatDiv28:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2636 case SnapToBeatDiv24:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2639 case SnapToBeatDiv20:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2642 case SnapToBeatDiv16:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2645 case SnapToBeatDiv14:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2648 case SnapToBeatDiv12:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2651 case SnapToBeatDiv10:
2652 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2654 case SnapToBeatDiv8:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2657 case SnapToBeatDiv7:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2660 case SnapToBeatDiv6:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2663 case SnapToBeatDiv5:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2666 case SnapToBeatDiv4:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2669 case SnapToBeatDiv3:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2672 case SnapToBeatDiv2:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2681 _session->locations()->marks_either_side (start, before, after);
2683 if (before == max_framepos && after == max_framepos) {
2684 /* No marks to snap to, so just don't snap */
2686 } else if (before == max_framepos) {
2688 } else if (after == max_framepos) {
2690 } else if (before != max_framepos && after != max_framepos) {
2691 /* have before and after */
2692 if ((start - before) < (after - start)) {
2701 case SnapToRegionStart:
2702 case SnapToRegionEnd:
2703 case SnapToRegionSync:
2704 case SnapToRegionBoundary:
2705 if (!region_boundary_cache.empty()) {
2707 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2708 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2710 if (direction > 0) {
2711 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2713 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2716 if (next != region_boundary_cache.begin ()) {
2721 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2722 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2724 if (start > (p + n) / 2) {
2733 switch (_snap_mode) {
2739 if (presnap > start) {
2740 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2744 } else if (presnap < start) {
2745 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2751 /* handled at entry */
2759 Editor::setup_toolbar ()
2761 HBox* mode_box = manage(new HBox);
2762 mode_box->set_border_width (2);
2763 mode_box->set_spacing(2);
2765 HBox* mouse_mode_box = manage (new HBox);
2766 HBox* mouse_mode_hbox = manage (new HBox);
2767 VBox* mouse_mode_vbox = manage (new VBox);
2768 Alignment* mouse_mode_align = manage (new Alignment);
2770 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2771 //mouse_mode_size_group->add_widget (smart_mode_button);
2772 mouse_mode_size_group->add_widget (mouse_move_button);
2773 mouse_mode_size_group->add_widget (mouse_cut_button);
2774 mouse_mode_size_group->add_widget (mouse_select_button);
2775 mouse_mode_size_group->add_widget (mouse_zoom_button);
2776 mouse_mode_size_group->add_widget (mouse_gain_button);
2777 mouse_mode_size_group->add_widget (mouse_timefx_button);
2778 mouse_mode_size_group->add_widget (mouse_audition_button);
2779 mouse_mode_size_group->add_widget (mouse_draw_button);
2780 mouse_mode_size_group->add_widget (internal_edit_button);
2782 if (!ARDOUR::Profile->get_small_screen()) {
2783 /* make them just a bit bigger */
2784 mouse_move_button.set_size_request (24, 30);
2786 /* make them just a bit taller */
2787 mouse_move_button.set_size_request (-1, 30);
2789 mouse_mode_hbox->set_spacing (2);
2791 if (!ARDOUR::Profile->get_trx()) {
2792 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2795 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2796 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2797 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2798 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2800 if (!ARDOUR::Profile->get_trx()) {
2801 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2802 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2803 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2804 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2805 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2808 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2810 mouse_mode_align->add (*mouse_mode_vbox);
2811 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2813 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2815 edit_mode_selector.set_name ("mouse mode button");
2816 set_size_request_to_display_given_text (edit_mode_selector, _("Ripple"), 30, 2);
2817 edit_mode_selector.add_elements (ArdourButton::Inset);
2819 if (!ARDOUR::Profile->get_trx()) {
2820 mode_box->pack_start (edit_mode_selector, false, false);
2822 mode_box->pack_start (*mouse_mode_box, false, false);
2824 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2825 _mouse_mode_tearoff->set_name ("MouseModeBase");
2826 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2828 if (Profile->get_sae()) {
2829 _mouse_mode_tearoff->set_can_be_torn_off (false);
2832 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2833 &_mouse_mode_tearoff->tearoff_window()));
2834 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2835 &_mouse_mode_tearoff->tearoff_window(), 1));
2836 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2837 &_mouse_mode_tearoff->tearoff_window()));
2838 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2839 &_mouse_mode_tearoff->tearoff_window(), 1));
2843 _zoom_box.set_spacing (2);
2844 _zoom_box.set_border_width (2);
2848 zoom_in_button.set_name ("zoom button");
2849 // zoom_in_button.add_elements ( ArdourButton::Inset );
2850 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2851 zoom_in_button.set_image(::get_icon ("zoom_in"));
2852 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2853 zoom_in_button.set_related_action (act);
2855 zoom_out_button.set_name ("zoom button");
2856 // zoom_out_button.add_elements ( ArdourButton::Inset );
2857 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2858 zoom_out_button.set_image(::get_icon ("zoom_out"));
2859 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2860 zoom_out_button.set_related_action (act);
2862 zoom_out_full_button.set_name ("zoom button");
2863 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2864 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2865 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2866 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2867 zoom_out_full_button.set_related_action (act);
2869 zoom_focus_selector.set_name ("zoom button");
2870 set_size_request_to_display_given_text (zoom_focus_selector, _("Edit Point"), 30, 2);
2871 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2873 if (!ARDOUR::Profile->get_trx()) {
2874 _zoom_box.pack_start (zoom_out_button, false, false);
2875 _zoom_box.pack_start (zoom_in_button, false, false);
2876 _zoom_box.pack_start (zoom_out_full_button, false, false);
2877 _zoom_box.pack_start (zoom_focus_selector, false, false);
2879 mode_box->pack_start (zoom_out_button, false, false);
2880 mode_box->pack_start (zoom_in_button, false, false);
2883 /* Track zoom buttons */
2884 visible_tracks_selector.set_name ("zoom button");
2885 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2886 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2888 tav_expand_button.set_name ("zoom button");
2889 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2890 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2891 tav_expand_button.set_size_request (-1, 20);
2892 tav_expand_button.set_image(::get_icon ("tav_exp"));
2893 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2894 tav_expand_button.set_related_action (act);
2896 tav_shrink_button.set_name ("zoom button");
2897 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2898 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2899 tav_shrink_button.set_size_request (-1, 20);
2900 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2901 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2902 tav_shrink_button.set_related_action (act);
2904 if (!ARDOUR::Profile->get_trx()) {
2905 _zoom_box.pack_start (visible_tracks_selector);
2907 _zoom_box.pack_start (tav_shrink_button);
2908 _zoom_box.pack_start (tav_expand_button);
2910 if (!ARDOUR::Profile->get_trx()) {
2911 _zoom_tearoff = manage (new TearOff (_zoom_box));
2913 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2914 &_zoom_tearoff->tearoff_window()));
2915 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2916 &_zoom_tearoff->tearoff_window(), 0));
2917 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918 &_zoom_tearoff->tearoff_window()));
2919 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920 &_zoom_tearoff->tearoff_window(), 0));
2923 snap_box.set_spacing (2);
2924 snap_box.set_border_width (2);
2926 snap_type_selector.set_name ("mouse mode button");
2927 snap_type_selector.add_elements (ArdourButton::Inset);
2928 set_size_request_to_display_given_text (snap_type_selector, _("Region starts"), 34, 2);
2930 snap_mode_selector.set_name ("mouse mode button");
2931 snap_mode_selector.add_elements (ArdourButton::Inset);
2932 set_size_request_to_display_given_text (snap_mode_selector, _("Magnetic"), 34, 2);
2934 edit_point_selector.set_name ("mouse mode button");
2935 edit_point_selector.add_elements (ArdourButton::Inset);
2936 set_size_request_to_display_given_text (edit_point_selector, _("Playhead"), 34, 2);
2938 snap_box.pack_start (snap_mode_selector, false, false);
2939 snap_box.pack_start (snap_type_selector, false, false);
2940 snap_box.pack_start (edit_point_selector, false, false);
2944 HBox *nudge_box = manage (new HBox);
2945 nudge_box->set_spacing (2);
2946 nudge_box->set_border_width (2);
2948 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2949 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2951 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2952 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2954 nudge_box->pack_start (nudge_backward_button, false, false);
2955 nudge_box->pack_start (nudge_forward_button, false, false);
2956 nudge_box->pack_start (*nudge_clock, false, false);
2959 /* Pack everything in... */
2961 HBox* hbox = manage (new HBox);
2962 hbox->set_spacing(2);
2964 _tools_tearoff = manage (new TearOff (*hbox));
2965 _tools_tearoff->set_name ("MouseModeBase");
2966 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2968 if (Profile->get_sae()) {
2969 _tools_tearoff->set_can_be_torn_off (false);
2972 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2973 &_tools_tearoff->tearoff_window()));
2974 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2975 &_tools_tearoff->tearoff_window(), 0));
2976 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2977 &_tools_tearoff->tearoff_window()));
2978 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2979 &_tools_tearoff->tearoff_window(), 0));
2981 toolbar_hbox.set_spacing (2);
2982 toolbar_hbox.set_border_width (1);
2984 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2985 if (!ARDOUR::Profile->get_trx()) {
2986 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2987 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2990 if (!ARDOUR::Profile->get_trx()) {
2991 hbox->pack_start (snap_box, false, false);
2992 if (!Profile->get_small_screen()) {
2993 hbox->pack_start (*nudge_box, false, false);
2995 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2998 hbox->pack_start (panic_box, false, false);
3002 toolbar_base.set_name ("ToolBarBase");
3003 toolbar_base.add (toolbar_hbox);
3005 _toolbar_viewport.add (toolbar_base);
3006 /* stick to the required height but allow width to vary if there's not enough room */
3007 _toolbar_viewport.set_size_request (1, -1);
3009 toolbar_frame.set_shadow_type (SHADOW_OUT);
3010 toolbar_frame.set_name ("BaseFrame");
3011 toolbar_frame.add (_toolbar_viewport);
3015 Editor::build_edit_point_menu ()
3017 using namespace Menu_Helpers;
3019 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3020 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3021 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3025 Editor::build_edit_mode_menu ()
3027 using namespace Menu_Helpers;
3029 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3030 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3031 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Ripple), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3032 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3036 Editor::build_snap_mode_menu ()
3038 using namespace Menu_Helpers;
3040 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3041 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3042 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3046 Editor::build_snap_type_menu ()
3048 using namespace Menu_Helpers;
3050 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3051 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3052 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3053 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3054 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3055 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3056 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3057 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3058 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3059 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3060 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3061 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3062 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3083 Editor::setup_tooltips ()
3085 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3086 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3087 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3088 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3089 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3090 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3091 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3092 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3093 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3094 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3095 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3096 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3097 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3098 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3099 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3100 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3101 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3102 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3103 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3104 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3105 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3106 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3107 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3108 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3109 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3113 Editor::convert_drop_to_paths (
3114 vector<string>& paths,
3115 const RefPtr<Gdk::DragContext>& /*context*/,
3118 const SelectionData& data,
3122 if (_session == 0) {
3126 vector<string> uris = data.get_uris();
3130 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3131 are actually URI lists. So do it by hand.
3134 if (data.get_target() != "text/plain") {
3138 /* Parse the "uri-list" format that Nautilus provides,
3139 where each pathname is delimited by \r\n.
3141 THERE MAY BE NO NULL TERMINATING CHAR!!!
3144 string txt = data.get_text();
3148 p = (char *) malloc (txt.length() + 1);
3149 txt.copy (p, txt.length(), 0);
3150 p[txt.length()] = '\0';
3156 while (g_ascii_isspace (*p))
3160 while (*q && (*q != '\n') && (*q != '\r')) {
3167 while (q > p && g_ascii_isspace (*q))
3172 uris.push_back (string (p, q - p + 1));
3176 p = strchr (p, '\n');
3188 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3189 if ((*i).substr (0,7) == "file://") {
3190 paths.push_back (Glib::filename_from_uri (*i));
3198 Editor::new_tempo_section ()
3203 Editor::map_transport_state ()
3205 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3207 if (_session && _session->transport_stopped()) {
3208 have_pending_keyboard_selection = false;
3211 update_loop_range_view ();
3217 Editor::begin_reversible_command (string name)
3220 _session->begin_reversible_command (name);
3225 Editor::begin_reversible_command (GQuark q)
3228 _session->begin_reversible_command (q);
3233 Editor::commit_reversible_command ()
3236 _session->commit_reversible_command ();
3241 Editor::history_changed ()
3245 if (undo_action && _session) {
3246 if (_session->undo_depth() == 0) {
3247 label = S_("Command|Undo");
3249 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3251 undo_action->property_label() = label;
3254 if (redo_action && _session) {
3255 if (_session->redo_depth() == 0) {
3258 label = string_compose(_("Redo (%1)"), _session->next_redo());
3260 redo_action->property_label() = label;
3265 Editor::duplicate_range (bool with_dialog)
3269 RegionSelection rs = get_regions_from_selection_and_entered ();
3271 if ( selection->time.length() == 0 && rs.empty()) {
3277 ArdourDialog win (_("Duplicate"));
3278 Label label (_("Number of duplications:"));
3279 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3280 SpinButton spinner (adjustment, 0.0, 1);
3283 win.get_vbox()->set_spacing (12);
3284 win.get_vbox()->pack_start (hbox);
3285 hbox.set_border_width (6);
3286 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3288 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3289 place, visually. so do this by hand.
3292 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3293 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3294 spinner.grab_focus();
3300 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3301 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3302 win.set_default_response (RESPONSE_ACCEPT);
3304 spinner.grab_focus ();
3306 switch (win.run ()) {
3307 case RESPONSE_ACCEPT:
3313 times = adjustment.get_value();
3316 if ((current_mouse_mode() == Editing::MouseRange)) {
3317 if (selection->time.length()) {
3318 duplicate_selection (times);
3320 } else if (get_smart_mode()) {
3321 if (selection->time.length()) {
3322 duplicate_selection (times);
3324 duplicate_some_regions (rs, times);
3326 duplicate_some_regions (rs, times);
3331 Editor::set_edit_mode (EditMode m)
3333 Config->set_edit_mode (m);
3337 Editor::cycle_edit_mode ()
3339 switch (Config->get_edit_mode()) {
3341 if (Profile->get_sae()) {
3342 Config->set_edit_mode (Lock);
3344 Config->set_edit_mode (Ripple);
3349 Config->set_edit_mode (Lock);
3352 Config->set_edit_mode (Slide);
3358 Editor::edit_mode_selection_done ( EditMode m )
3360 Config->set_edit_mode ( m );
3364 Editor::snap_type_selection_done (SnapType snaptype)
3366 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3368 ract->set_active ();
3373 Editor::snap_mode_selection_done (SnapMode mode)
3375 RefPtr<RadioAction> ract = snap_mode_action (mode);
3378 ract->set_active (true);
3383 Editor::cycle_edit_point (bool with_marker)
3385 switch (_edit_point) {
3387 set_edit_point_preference (EditAtPlayhead);
3389 case EditAtPlayhead:
3391 set_edit_point_preference (EditAtSelectedMarker);
3393 set_edit_point_preference (EditAtMouse);
3396 case EditAtSelectedMarker:
3397 set_edit_point_preference (EditAtMouse);
3403 Editor::edit_point_selection_done (EditPoint ep)
3405 set_edit_point_preference ( ep );
3409 Editor::build_zoom_focus_menu ()
3411 using namespace Menu_Helpers;
3413 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3414 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3415 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3416 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3417 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3418 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3422 Editor::zoom_focus_selection_done ( ZoomFocus f )
3424 RefPtr<RadioAction> ract = zoom_focus_action (f);
3426 ract->set_active ();
3431 Editor::build_track_count_menu ()
3433 using namespace Menu_Helpers;
3435 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3436 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3437 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3438 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3439 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3440 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3441 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3442 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3443 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3444 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3445 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3446 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3450 Editor::set_visible_track_count (int32_t n)
3452 _visible_track_count = n;
3454 /* if the canvas hasn't really been allocated any size yet, just
3455 record the desired number of visible tracks and return. when canvas
3456 allocation happens, we will get called again and then we can do the
3460 if (_visible_canvas_height <= 1) {
3467 if (_visible_track_count > 0) {
3468 h = _visible_canvas_height / _visible_track_count;
3469 std::ostringstream s;
3470 s << _visible_track_count;
3472 } else if (_visible_track_count == 0) {
3473 h = _visible_canvas_height / track_views.size();
3476 /* negative value means that the visible track count has
3477 been overridden by explicit track height changes.
3479 visible_tracks_selector.set_text (X_("*"));
3483 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3484 (*i)->set_height (h);
3487 if (str != visible_tracks_selector.get_text()) {
3488 visible_tracks_selector.set_text (str);
3493 Editor::override_visible_track_count ()
3495 _visible_track_count = -_visible_track_count;
3499 Editor::edit_controls_button_release (GdkEventButton* ev)
3501 if (Keyboard::is_context_menu_event (ev)) {
3502 ARDOUR_UI::instance()->add_route (this);
3503 } else if (ev->button == 1) {
3504 selection->clear_tracks ();
3511 Editor::mouse_select_button_release (GdkEventButton* ev)
3513 /* this handles just right-clicks */
3515 if (ev->button != 3) {
3523 Editor::set_zoom_focus (ZoomFocus f)
3525 string str = zoom_focus_strings[(int)f];
3527 if (str != zoom_focus_selector.get_text()) {
3528 zoom_focus_selector.set_text (str);
3531 if (zoom_focus != f) {
3538 Editor::cycle_zoom_focus ()
3540 switch (zoom_focus) {
3542 set_zoom_focus (ZoomFocusRight);
3544 case ZoomFocusRight:
3545 set_zoom_focus (ZoomFocusCenter);
3547 case ZoomFocusCenter:
3548 set_zoom_focus (ZoomFocusPlayhead);
3550 case ZoomFocusPlayhead:
3551 set_zoom_focus (ZoomFocusMouse);
3553 case ZoomFocusMouse:
3554 set_zoom_focus (ZoomFocusEdit);
3557 set_zoom_focus (ZoomFocusLeft);
3563 Editor::ensure_float (Window& win)
3565 win.set_transient_for (*this);
3569 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3571 /* recover or initialize pane positions. do this here rather than earlier because
3572 we don't want the positions to change the child allocations, which they seem to do.
3578 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3587 XMLNode* geometry = find_named_node (*node, "geometry");
3589 if (which == static_cast<Paned*> (&edit_pane)) {
3591 if (done & Horizontal) {
3595 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3596 _notebook_shrunk = string_is_affirmative (prop->value ());
3599 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3600 /* initial allocation is 90% to canvas, 10% to notebook */
3601 pos = (int) floor (alloc.get_width() * 0.90f);
3602 snprintf (buf, sizeof(buf), "%d", pos);
3604 pos = atoi (prop->value());
3607 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3608 edit_pane.set_position (pos);
3611 done = (Pane) (done | Horizontal);
3613 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3615 if (done & Vertical) {
3619 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3620 /* initial allocation is 90% to canvas, 10% to summary */
3621 pos = (int) floor (alloc.get_height() * 0.90f);
3622 snprintf (buf, sizeof(buf), "%d", pos);
3625 pos = atoi (prop->value());
3628 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3629 editor_summary_pane.set_position (pos);
3632 done = (Pane) (done | Vertical);
3637 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3639 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3640 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3641 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3642 top_hbox.remove (toolbar_frame);
3647 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3649 if (toolbar_frame.get_parent() == 0) {
3650 top_hbox.pack_end (toolbar_frame);
3655 Editor::set_show_measures (bool yn)
3657 if (_show_measures != yn) {
3660 if ((_show_measures = yn) == true) {
3662 tempo_lines->show();
3665 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3666 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3668 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3669 draw_measures (begin, end);
3677 Editor::toggle_follow_playhead ()
3679 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3681 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3682 set_follow_playhead (tact->get_active());
3686 /** @param yn true to follow playhead, otherwise false.
3687 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3690 Editor::set_follow_playhead (bool yn, bool catch_up)
3692 if (_follow_playhead != yn) {
3693 if ((_follow_playhead = yn) == true && catch_up) {
3695 reset_x_origin_to_follow_playhead ();
3702 Editor::toggle_stationary_playhead ()
3704 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3706 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3707 set_stationary_playhead (tact->get_active());
3712 Editor::set_stationary_playhead (bool yn)
3714 if (_stationary_playhead != yn) {
3715 if ((_stationary_playhead = yn) == true) {
3717 // FIXME need a 3.0 equivalent of this 2.X call
3718 // update_current_screen ();
3725 Editor::playlist_selector () const
3727 return *_playlist_selector;
3731 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3735 switch (_snap_type) {
3740 case SnapToBeatDiv128:
3743 case SnapToBeatDiv64:
3746 case SnapToBeatDiv32:
3749 case SnapToBeatDiv28:
3752 case SnapToBeatDiv24:
3755 case SnapToBeatDiv20:
3758 case SnapToBeatDiv16:
3761 case SnapToBeatDiv14:
3764 case SnapToBeatDiv12:
3767 case SnapToBeatDiv10:
3770 case SnapToBeatDiv8:
3773 case SnapToBeatDiv7:
3776 case SnapToBeatDiv6:
3779 case SnapToBeatDiv5:
3782 case SnapToBeatDiv4:
3785 case SnapToBeatDiv3:
3788 case SnapToBeatDiv2:
3794 return _session->tempo_map().meter_at (position).divisions_per_bar();
3799 case SnapToTimecodeFrame:
3800 case SnapToTimecodeSeconds:
3801 case SnapToTimecodeMinutes:
3804 case SnapToRegionStart:
3805 case SnapToRegionEnd:
3806 case SnapToRegionSync:
3807 case SnapToRegionBoundary:
3817 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3821 ret = nudge_clock->current_duration (pos);
3822 next = ret + 1; /* XXXX fix me */
3828 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3830 ArdourDialog dialog (_("Playlist Deletion"));
3831 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3832 "If it is kept, its audio files will not be cleaned.\n"
3833 "If it is deleted, audio files used by it alone will be cleaned."),
3836 dialog.set_position (WIN_POS_CENTER);
3837 dialog.get_vbox()->pack_start (label);
3841 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3842 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3843 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3845 switch (dialog.run ()) {
3846 case RESPONSE_ACCEPT:
3847 /* delete the playlist */
3851 case RESPONSE_REJECT:
3852 /* keep the playlist */
3864 Editor::audio_region_selection_covers (framepos_t where)
3866 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3867 if ((*a)->region()->covers (where)) {
3876 Editor::prepare_for_cleanup ()
3878 cut_buffer->clear_regions ();
3879 cut_buffer->clear_playlists ();
3881 selection->clear_regions ();
3882 selection->clear_playlists ();
3884 _regions->suspend_redisplay ();
3888 Editor::finish_cleanup ()
3890 _regions->resume_redisplay ();
3894 Editor::transport_loop_location()
3897 return _session->locations()->auto_loop_location();
3904 Editor::transport_punch_location()
3907 return _session->locations()->auto_punch_location();
3914 Editor::control_layout_scroll (GdkEventScroll* ev)
3916 /* Just forward to the normal canvas scroll method. The coordinate
3917 systems are different but since the canvas is always larger than the
3918 track headers, and aligned with the trackview area, this will work.
3920 In the not too distant future this layout is going away anyway and
3921 headers will be on the canvas.
3923 return canvas_scroll_event (ev, false);
3927 Editor::session_state_saved (string)
3930 _snapshots->redisplay ();
3934 Editor::update_tearoff_visibility()
3936 bool visible = Config->get_keep_tearoffs();
3937 _mouse_mode_tearoff->set_visible (visible);
3938 _tools_tearoff->set_visible (visible);
3939 if (_zoom_tearoff) {
3940 _zoom_tearoff->set_visible (visible);
3945 Editor::maximise_editing_space ()
3957 Editor::restore_editing_space ()
3969 * Make new playlists for a given track and also any others that belong
3970 * to the same active route group with the `select' property.
3975 Editor::new_playlists (TimeAxisView* v)
3977 begin_reversible_command (_("new playlists"));
3978 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3979 _session->playlists->get (playlists);
3980 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3981 commit_reversible_command ();
3985 * Use a copy of the current playlist for a given track and also any others that belong
3986 * to the same active route group with the `select' property.
3991 Editor::copy_playlists (TimeAxisView* v)
3993 begin_reversible_command (_("copy playlists"));
3994 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3995 _session->playlists->get (playlists);
3996 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3997 commit_reversible_command ();
4000 /** Clear the current playlist for a given track and also any others that belong
4001 * to the same active route group with the `select' property.
4006 Editor::clear_playlists (TimeAxisView* v)
4008 begin_reversible_command (_("clear playlists"));
4009 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4010 _session->playlists->get (playlists);
4011 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4012 commit_reversible_command ();
4016 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4018 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4022 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4024 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4028 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4030 atv.clear_playlist ();
4034 Editor::on_key_press_event (GdkEventKey* ev)
4036 return key_press_focus_accelerator_handler (*this, ev);
4040 Editor::on_key_release_event (GdkEventKey* ev)
4042 return Gtk::Window::on_key_release_event (ev);
4043 // return key_press_focus_accelerator_handler (*this, ev);
4046 /** Queue up a change to the viewport x origin.
4047 * @param frame New x origin.
4050 Editor::reset_x_origin (framepos_t frame)
4052 pending_visual_change.add (VisualChange::TimeOrigin);
4053 pending_visual_change.time_origin = frame;
4054 ensure_visual_change_idle_handler ();
4058 Editor::reset_y_origin (double y)
4060 pending_visual_change.add (VisualChange::YOrigin);
4061 pending_visual_change.y_origin = y;
4062 ensure_visual_change_idle_handler ();
4066 Editor::reset_zoom (framecnt_t spp)
4068 if (spp == samples_per_pixel) {
4072 pending_visual_change.add (VisualChange::ZoomLevel);
4073 pending_visual_change.samples_per_pixel = spp;
4074 ensure_visual_change_idle_handler ();
4078 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4080 reset_x_origin (frame);
4083 if (!no_save_visual) {
4084 undo_visual_stack.push_back (current_visual_state(false));
4088 Editor::VisualState::VisualState (bool with_tracks)
4089 : gui_state (with_tracks ? new GUIObjectState : 0)
4093 Editor::VisualState::~VisualState ()
4098 Editor::VisualState*
4099 Editor::current_visual_state (bool with_tracks)
4101 VisualState* vs = new VisualState (with_tracks);
4102 vs->y_position = vertical_adjustment.get_value();
4103 vs->samples_per_pixel = samples_per_pixel;
4104 vs->leftmost_frame = leftmost_frame;
4105 vs->zoom_focus = zoom_focus;
4108 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4115 Editor::undo_visual_state ()
4117 if (undo_visual_stack.empty()) {
4121 VisualState* vs = undo_visual_stack.back();
4122 undo_visual_stack.pop_back();
4125 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4127 use_visual_state (*vs);
4131 Editor::redo_visual_state ()
4133 if (redo_visual_stack.empty()) {
4137 VisualState* vs = redo_visual_stack.back();
4138 redo_visual_stack.pop_back();
4140 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4142 use_visual_state (*vs);
4146 Editor::swap_visual_state ()
4148 if (undo_visual_stack.empty()) {
4149 redo_visual_state ();
4151 undo_visual_state ();
4156 Editor::use_visual_state (VisualState& vs)
4158 PBD::Unwinder<bool> nsv (no_save_visual, true);
4159 DisplaySuspender ds;
4161 vertical_adjustment.set_value (vs.y_position);
4163 set_zoom_focus (vs.zoom_focus);
4164 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4167 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4169 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4170 (*i)->reset_visual_state ();
4174 _routes->update_visibility ();
4177 /** This is the core function that controls the zoom level of the canvas. It is called
4178 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4179 * @param spp new number of samples per pixel
4182 Editor::set_samples_per_pixel (framecnt_t spp)
4188 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4189 const framecnt_t lots_of_pixels = 4000;
4191 /* if the zoom level is greater than what you'd get trying to display 3
4192 * days of audio on a really big screen, then it's too big.
4195 if (spp * lots_of_pixels > three_days) {
4199 samples_per_pixel = spp;
4202 tempo_lines->tempo_map_changed();
4205 bool const showing_time_selection = selection->time.length() > 0;
4207 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4208 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4209 (*i)->reshow_selection (selection->time);
4213 ZoomChanged (); /* EMIT_SIGNAL */
4215 ArdourCanvas::GtkCanvasViewport* c;
4217 c = get_track_canvas();
4219 c->canvas()->zoomed ();
4222 if (playhead_cursor) {
4223 playhead_cursor->set_position (playhead_cursor->current_frame ());
4226 refresh_location_display();
4227 _summary->set_overlays_dirty ();
4229 update_marker_labels ();
4235 Editor::queue_visual_videotimeline_update ()
4238 * pending_visual_change.add (VisualChange::VideoTimeline);
4239 * or maybe even more specific: which videotimeline-image
4240 * currently it calls update_video_timeline() to update
4241 * _all outdated_ images on the video-timeline.
4242 * see 'exposeimg()' in video_image_frame.cc
4244 ensure_visual_change_idle_handler ();
4248 Editor::ensure_visual_change_idle_handler ()
4250 if (pending_visual_change.idle_handler_id < 0) {
4251 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4252 pending_visual_change.being_handled = false;
4257 Editor::_idle_visual_changer (void* arg)
4259 return static_cast<Editor*>(arg)->idle_visual_changer ();
4263 Editor::idle_visual_changer ()
4265 /* set_horizontal_position() below (and maybe other calls) call
4266 gtk_main_iteration(), so it's possible that a signal will be handled
4267 half-way through this method. If this signal wants an
4268 idle_visual_changer we must schedule another one after this one, so
4269 mark the idle_handler_id as -1 here to allow that. Also make a note
4270 that we are doing the visual change, so that changes in response to
4271 super-rapid-screen-update can be dropped if we are still processing
4275 pending_visual_change.idle_handler_id = -1;
4276 pending_visual_change.being_handled = true;
4278 VisualChange vc = pending_visual_change;
4280 pending_visual_change.pending = (VisualChange::Type) 0;
4282 visual_changer (vc);
4284 pending_visual_change.being_handled = false;
4286 return 0; /* this is always a one-shot call */
4290 Editor::visual_changer (const VisualChange& vc)
4292 double const last_time_origin = horizontal_position ();
4294 if (vc.pending & VisualChange::ZoomLevel) {
4295 set_samples_per_pixel (vc.samples_per_pixel);
4297 compute_fixed_ruler_scale ();
4299 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4300 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4302 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4303 current_bbt_points_begin, current_bbt_points_end);
4304 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4305 current_bbt_points_begin, current_bbt_points_end);
4306 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4308 update_video_timeline();
4311 if (vc.pending & VisualChange::TimeOrigin) {
4312 set_horizontal_position (vc.time_origin / samples_per_pixel);
4315 if (vc.pending & VisualChange::YOrigin) {
4316 vertical_adjustment.set_value (vc.y_origin);
4319 if (last_time_origin == horizontal_position ()) {
4320 /* changed signal not emitted */
4321 update_fixed_rulers ();
4322 redisplay_tempo (true);
4325 if (!(vc.pending & VisualChange::ZoomLevel)) {
4326 update_video_timeline();
4329 _summary->set_overlays_dirty ();
4332 struct EditorOrderTimeAxisSorter {
4333 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4334 return a->order () < b->order ();
4339 Editor::sort_track_selection (TrackViewList& sel)
4341 EditorOrderTimeAxisSorter cmp;
4346 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4349 framepos_t where = 0;
4350 EditPoint ep = _edit_point;
4352 if (from_context_menu && (ep == EditAtMouse)) {
4353 return canvas_event_sample (&context_click_event, 0, 0);
4356 if (entered_marker) {
4357 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4358 return entered_marker->position();
4361 if (ignore_playhead && ep == EditAtPlayhead) {
4362 ep = EditAtSelectedMarker;
4366 case EditAtPlayhead:
4367 where = _session->audible_frame();
4368 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4371 case EditAtSelectedMarker:
4372 if (!selection->markers.empty()) {
4374 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4377 where = loc->start();
4381 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4389 if (!mouse_frame (where, ignored)) {
4390 /* XXX not right but what can we do ? */
4394 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4402 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4404 if (!_session) return;
4406 begin_reversible_command (cmd);
4410 if ((tll = transport_loop_location()) == 0) {
4411 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4412 XMLNode &before = _session->locations()->get_state();
4413 _session->locations()->add (loc, true);
4414 _session->set_auto_loop_location (loc);
4415 XMLNode &after = _session->locations()->get_state();
4416 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4418 XMLNode &before = tll->get_state();
4419 tll->set_hidden (false, this);
4420 tll->set (start, end);
4421 XMLNode &after = tll->get_state();
4422 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4425 commit_reversible_command ();
4429 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4431 if (!_session) return;
4433 begin_reversible_command (cmd);
4437 if ((tpl = transport_punch_location()) == 0) {
4438 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4439 XMLNode &before = _session->locations()->get_state();
4440 _session->locations()->add (loc, true);
4441 _session->set_auto_punch_location (loc);
4442 XMLNode &after = _session->locations()->get_state();
4443 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4446 XMLNode &before = tpl->get_state();
4447 tpl->set_hidden (false, this);
4448 tpl->set (start, end);
4449 XMLNode &after = tpl->get_state();
4450 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4453 commit_reversible_command ();
4456 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4457 * @param rs List to which found regions are added.
4458 * @param where Time to look at.
4459 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4462 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4464 const TrackViewList* tracks;
4467 tracks = &track_views;
4472 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4474 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4477 boost::shared_ptr<Track> tr;
4478 boost::shared_ptr<Playlist> pl;
4480 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4482 boost::shared_ptr<RegionList> regions = pl->regions_at (
4483 (framepos_t) floor ( (double) where * tr->speed()));
4485 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4486 RegionView* rv = rtv->view()->find_view (*i);
4497 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4499 const TrackViewList* tracks;
4502 tracks = &track_views;
4507 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4508 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4510 boost::shared_ptr<Track> tr;
4511 boost::shared_ptr<Playlist> pl;
4513 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4515 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4516 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4518 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4520 RegionView* rv = rtv->view()->find_view (*i);
4531 /** Get regions using the following method:
4533 * Make a region list using:
4534 * (a) any selected regions
4535 * (b) the intersection of any selected tracks and the edit point(*)
4536 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4538 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4540 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4544 Editor::get_regions_from_selection_and_edit_point ()
4546 RegionSelection regions;
4548 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4549 regions.add (entered_regionview);
4551 regions = selection->regions;
4554 if ( regions.empty() ) {
4555 TrackViewList tracks = selection->tracks;
4557 if (!tracks.empty()) {
4558 /* no region selected or entered, but some selected tracks:
4559 * act on all regions on the selected tracks at the edit point
4561 framepos_t const where = get_preferred_edit_position ();
4562 get_regions_at(regions, where, tracks);
4569 /** Get regions using the following method:
4571 * Make a region list using:
4572 * (a) any selected regions
4573 * (b) the intersection of any selected tracks and the edit point(*)
4574 * (c) if neither exists, then whatever region is under the mouse
4576 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4578 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4581 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4583 RegionSelection regions;
4585 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4586 regions.add (entered_regionview);
4588 regions = selection->regions;
4591 if ( regions.empty() ) {
4592 TrackViewList tracks = selection->tracks;
4594 if (!tracks.empty()) {
4595 /* no region selected or entered, but some selected tracks:
4596 * act on all regions on the selected tracks at the edit point
4598 get_regions_at(regions, pos, tracks);
4605 /** Start with regions that are selected, or the entered regionview if none are selected.
4606 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4607 * of the regions that we started with.
4611 Editor::get_regions_from_selection_and_entered ()
4613 RegionSelection regions = selection->regions;
4615 if (regions.empty() && entered_regionview) {
4616 regions.add (entered_regionview);
4623 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4627 RouteTimeAxisView* tatv;
4629 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4631 boost::shared_ptr<Playlist> pl;
4632 vector<boost::shared_ptr<Region> > results;
4634 boost::shared_ptr<Track> tr;
4636 if ((tr = tatv->track()) == 0) {
4641 if ((pl = (tr->playlist())) != 0) {
4642 if (src_comparison) {
4643 pl->get_source_equivalent_regions (region, results);
4645 pl->get_region_list_equivalent_regions (region, results);
4649 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4650 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4651 regions.push_back (marv);
4660 Editor::show_rhythm_ferret ()
4662 if (rhythm_ferret == 0) {
4663 rhythm_ferret = new RhythmFerret(*this);
4666 rhythm_ferret->set_session (_session);
4667 rhythm_ferret->show ();
4668 rhythm_ferret->present ();
4672 Editor::first_idle ()
4674 MessageDialog* dialog = 0;
4676 if (track_views.size() > 1) {
4677 dialog = new MessageDialog (
4679 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4683 ARDOUR_UI::instance()->flush_pending ();
4686 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4690 // first idle adds route children (automation tracks), so we need to redisplay here
4691 _routes->redisplay ();
4698 Editor::_idle_resize (gpointer arg)
4700 return ((Editor*)arg)->idle_resize ();
4704 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4706 if (resize_idle_id < 0) {
4707 resize_idle_id = g_idle_add (_idle_resize, this);
4708 _pending_resize_amount = 0;
4711 /* make a note of the smallest resulting height, so that we can clamp the
4712 lower limit at TimeAxisView::hSmall */
4714 int32_t min_resulting = INT32_MAX;
4716 _pending_resize_amount += h;
4717 _pending_resize_view = view;
4719 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4721 if (selection->tracks.contains (_pending_resize_view)) {
4722 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4723 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4727 if (min_resulting < 0) {
4732 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4733 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4737 /** Handle pending resizing of tracks */
4739 Editor::idle_resize ()
4741 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4743 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4744 selection->tracks.contains (_pending_resize_view)) {
4746 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4747 if (*i != _pending_resize_view) {
4748 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4753 _pending_resize_amount = 0;
4754 _group_tabs->set_dirty ();
4755 resize_idle_id = -1;
4763 ENSURE_GUI_THREAD (*this, &Editor::located);
4766 playhead_cursor->set_position (_session->audible_frame ());
4767 if (_follow_playhead && !_pending_initial_locate) {
4768 reset_x_origin_to_follow_playhead ();
4772 _pending_locate_request = false;
4773 _pending_initial_locate = false;
4777 Editor::region_view_added (RegionView *)
4779 _summary->set_background_dirty ();
4783 Editor::region_view_removed ()
4785 _summary->set_background_dirty ();
4789 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4791 TrackViewList::const_iterator j = track_views.begin ();
4792 while (j != track_views.end()) {
4793 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4794 if (rtv && rtv->route() == r) {
4805 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4809 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4810 TimeAxisView* tv = axis_view_from_route (*i);
4820 Editor::suspend_route_redisplay ()
4823 _routes->suspend_redisplay();
4828 Editor::resume_route_redisplay ()
4831 _routes->resume_redisplay();
4836 Editor::add_routes (RouteList& routes)
4838 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4840 RouteTimeAxisView *rtv;
4841 list<RouteTimeAxisView*> new_views;
4843 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4844 boost::shared_ptr<Route> route = (*x);
4846 if (route->is_auditioner() || route->is_monitor()) {
4850 DataType dt = route->input()->default_type();
4852 if (dt == ARDOUR::DataType::AUDIO) {
4853 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4854 rtv->set_route (route);
4855 } else if (dt == ARDOUR::DataType::MIDI) {
4856 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4857 rtv->set_route (route);
4859 throw unknown_type();
4862 new_views.push_back (rtv);
4863 track_views.push_back (rtv);
4865 rtv->effective_gain_display ();
4867 if (internal_editing()) {
4868 rtv->enter_internal_edit_mode ();
4870 rtv->leave_internal_edit_mode ();
4873 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4874 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4877 if (new_views.size() > 0) {
4878 _routes->routes_added (new_views);
4879 _summary->routes_added (new_views);
4882 if (show_editor_mixer_when_tracks_arrive) {
4883 show_editor_mixer (true);
4886 editor_list_button.set_sensitive (true);
4890 Editor::timeaxisview_deleted (TimeAxisView *tv)
4892 if (tv == entered_track) {
4896 if (_session && _session->deletion_in_progress()) {
4897 /* the situation is under control */
4901 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4903 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4905 _routes->route_removed (tv);
4907 TimeAxisView::Children c = tv->get_child_list ();
4908 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4909 if (entered_track == i->get()) {
4914 /* remove it from the list of track views */
4916 TrackViewList::iterator i;
4918 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4919 i = track_views.erase (i);
4922 /* update whatever the current mixer strip is displaying, if revelant */
4924 boost::shared_ptr<Route> route;
4927 route = rtav->route ();
4930 if (current_mixer_strip && current_mixer_strip->route() == route) {
4932 TimeAxisView* next_tv;
4934 if (track_views.empty()) {
4936 } else if (i == track_views.end()) {
4937 next_tv = track_views.front();
4944 set_selected_mixer_strip (*next_tv);
4946 /* make the editor mixer strip go away setting the
4947 * button to inactive (which also unticks the menu option)
4950 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4956 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4958 if (apply_to_selection) {
4959 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4961 TrackSelection::iterator j = i;
4964 hide_track_in_display (*i, false);
4969 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4971 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4972 // this will hide the mixer strip
4973 set_selected_mixer_strip (*tv);
4976 _routes->hide_track_in_display (*tv);
4981 Editor::sync_track_view_list_and_routes ()
4983 track_views = TrackViewList (_routes->views ());
4985 _summary->set_dirty ();
4986 _group_tabs->set_dirty ();
4988 return false; // do not call again (until needed)
4992 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4994 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4999 /** Find a RouteTimeAxisView by the ID of its route */
5001 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5003 RouteTimeAxisView* v;
5005 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5006 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5007 if(v->route()->id() == id) {
5017 Editor::fit_route_group (RouteGroup *g)
5019 TrackViewList ts = axis_views_from_routes (g->route_list ());
5024 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5026 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5029 _session->cancel_audition ();
5033 if (_session->is_auditioning()) {
5034 _session->cancel_audition ();
5035 if (r == last_audition_region) {
5040 _session->audition_region (r);
5041 last_audition_region = r;
5046 Editor::hide_a_region (boost::shared_ptr<Region> r)
5048 r->set_hidden (true);
5052 Editor::show_a_region (boost::shared_ptr<Region> r)
5054 r->set_hidden (false);
5058 Editor::audition_region_from_region_list ()
5060 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5064 Editor::hide_region_from_region_list ()
5066 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5070 Editor::show_region_in_region_list ()
5072 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5076 Editor::step_edit_status_change (bool yn)
5079 start_step_editing ();
5081 stop_step_editing ();
5086 Editor::start_step_editing ()
5088 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5092 Editor::stop_step_editing ()
5094 step_edit_connection.disconnect ();
5098 Editor::check_step_edit ()
5100 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5101 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5103 mtv->check_step_edit ();
5107 return true; // do it again, till we stop
5111 Editor::scroll_press (Direction dir)
5113 ++_scroll_callbacks;
5115 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5116 /* delay the first auto-repeat */
5122 scroll_backward (1);
5130 scroll_tracks_up_line ();
5134 scroll_tracks_down_line ();
5138 /* do hacky auto-repeat */
5139 if (!_scroll_connection.connected ()) {
5141 _scroll_connection = Glib::signal_timeout().connect (
5142 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5145 _scroll_callbacks = 0;
5152 Editor::scroll_release ()
5154 _scroll_connection.disconnect ();
5157 /** Queue a change for the Editor viewport x origin to follow the playhead */
5159 Editor::reset_x_origin_to_follow_playhead ()
5161 framepos_t const frame = playhead_cursor->current_frame ();
5163 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5165 if (_session->transport_speed() < 0) {
5167 if (frame > (current_page_samples() / 2)) {
5168 center_screen (frame-(current_page_samples()/2));
5170 center_screen (current_page_samples()/2);
5177 if (frame < leftmost_frame) {
5179 if (_session->transport_rolling()) {
5180 /* rolling; end up with the playhead at the right of the page */
5181 l = frame - current_page_samples ();
5183 /* not rolling: end up with the playhead 1/4 of the way along the page */
5184 l = frame - current_page_samples() / 4;
5188 if (_session->transport_rolling()) {
5189 /* rolling: end up with the playhead on the left of the page */
5192 /* not rolling: end up with the playhead 3/4 of the way along the page */
5193 l = frame - 3 * current_page_samples() / 4;
5201 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5207 Editor::super_rapid_screen_update ()
5209 if (!_session || !_session->engine().running()) {
5213 /* METERING / MIXER STRIPS */
5215 /* update track meters, if required */
5216 if (is_mapped() && meters_running) {
5217 RouteTimeAxisView* rtv;
5218 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5219 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5220 rtv->fast_update ();
5225 /* and any current mixer strip */
5226 if (current_mixer_strip) {
5227 current_mixer_strip->fast_update ();
5230 /* PLAYHEAD AND VIEWPORT */
5232 framepos_t const frame = _session->audible_frame();
5234 /* There are a few reasons why we might not update the playhead / viewport stuff:
5236 * 1. we don't update things when there's a pending locate request, otherwise
5237 * when the editor requests a locate there is a chance that this method
5238 * will move the playhead before the locate request is processed, causing
5240 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5241 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5244 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5246 last_update_frame = frame;
5248 if (!_dragging_playhead) {
5249 playhead_cursor->set_position (frame);
5252 if (!_stationary_playhead) {
5254 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5255 /* We only do this if we aren't already
5256 handling a visual change (ie if
5257 pending_visual_change.being_handled is
5258 false) so that these requests don't stack
5259 up there are too many of them to handle in
5262 reset_x_origin_to_follow_playhead ();
5267 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5271 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5272 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5273 if (target <= 0.0) {
5276 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5277 target = (target * 0.15) + (current * 0.85);
5283 set_horizontal_position (current);
5292 Editor::session_going_away ()
5294 _have_idled = false;
5296 _session_connections.drop_connections ();
5298 super_rapid_screen_update_connection.disconnect ();
5300 selection->clear ();
5301 cut_buffer->clear ();
5303 clicked_regionview = 0;
5304 clicked_axisview = 0;
5305 clicked_routeview = 0;
5306 entered_regionview = 0;
5308 last_update_frame = 0;
5311 playhead_cursor->hide ();
5313 /* rip everything out of the list displays */
5317 _route_groups->clear ();
5319 /* do this first so that deleting a track doesn't reset cms to null
5320 and thus cause a leak.
5323 if (current_mixer_strip) {
5324 if (current_mixer_strip->get_parent() != 0) {
5325 global_hpacker.remove (*current_mixer_strip);
5327 delete current_mixer_strip;
5328 current_mixer_strip = 0;
5331 /* delete all trackviews */
5333 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5336 track_views.clear ();
5338 nudge_clock->set_session (0);
5340 editor_list_button.set_active(false);
5341 editor_list_button.set_sensitive(false);
5343 /* clear tempo/meter rulers */
5344 remove_metric_marks ();
5346 clear_marker_display ();
5348 stop_step_editing ();
5350 /* get rid of any existing editor mixer strip */
5352 WindowTitle title(Glib::get_application_name());
5353 title += _("Editor");
5355 set_title (title.get_string());
5357 SessionHandlePtr::session_going_away ();
5362 Editor::show_editor_list (bool yn)
5365 _the_notebook.show ();
5367 _the_notebook.hide ();
5372 Editor::change_region_layering_order (bool from_context_menu)
5374 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5376 if (!clicked_routeview) {
5377 if (layering_order_editor) {
5378 layering_order_editor->hide ();
5383 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5389 boost::shared_ptr<Playlist> pl = track->playlist();
5395 if (layering_order_editor == 0) {
5396 layering_order_editor = new RegionLayeringOrderEditor (*this);
5399 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5400 layering_order_editor->maybe_present ();
5404 Editor::update_region_layering_order_editor ()
5406 if (layering_order_editor && layering_order_editor->is_visible ()) {
5407 change_region_layering_order (true);
5412 Editor::setup_fade_images ()
5414 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5415 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5416 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5417 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5418 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5420 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5421 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5422 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5423 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5424 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5426 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5427 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5428 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5429 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5430 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5432 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5433 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5434 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5435 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5436 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5440 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5442 Editor::action_menu_item (std::string const & name)
5444 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5447 return *manage (a->create_menu_item ());
5451 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5453 EventBox* b = manage (new EventBox);
5454 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5455 Label* l = manage (new Label (name));
5459 _the_notebook.append_page (widget, *b);
5463 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5465 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5466 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5469 if (ev->type == GDK_2BUTTON_PRESS) {
5471 /* double-click on a notebook tab shrinks or expands the notebook */
5473 if (_notebook_shrunk) {
5474 if (pre_notebook_shrink_pane_width) {
5475 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5477 _notebook_shrunk = false;
5479 pre_notebook_shrink_pane_width = edit_pane.get_position();
5481 /* this expands the LHS of the edit pane to cover the notebook
5482 PAGE but leaves the tabs visible.
5484 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5485 _notebook_shrunk = true;
5493 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5495 using namespace Menu_Helpers;
5497 MenuList& items = _control_point_context_menu.items ();
5500 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5501 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5502 if (!can_remove_control_point (item)) {
5503 items.back().set_sensitive (false);
5506 _control_point_context_menu.popup (event->button.button, event->button.time);
5510 Editor::zoom_vertical_modifier_released()
5512 _stepping_axis_view = 0;
5516 Editor::ui_parameter_changed (string parameter)
5518 if (parameter == "icon-set") {
5519 while (!_cursor_stack.empty()) {
5520 _cursor_stack.pop();
5522 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5523 } else if (parameter == "draggable-playhead") {
5524 if (_verbose_cursor) {
5525 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());