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/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "grid_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_grid_type_strings[] = {
172 N_("1/3 (8th triplet)"), // or "1/12" ?
173 N_("1/6 (16th triplet)"),
174 N_("1/12 (32nd triplet)"),
175 N_("1/24 (64th triplet)"),
176 N_("1/5 (8th quintuplet)"),
177 N_("1/10 (16th quintuplet)"),
178 N_("1/20 (32nd quintuplet)"),
179 N_("1/7 (8th septuplet)"),
180 N_("1/14 (16th septuplet)"),
181 N_("1/28 (32nd septuplet)"),
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 //Robin says: this should be odd to accomodate cairo drawing offset ( width/2 rounds up to pixel boundary )
227 #define COMBO_TRIANGLE_WIDTH 11 // as-measured. was 25: ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 : PublicEditor (global_hpacker)
231 , editor_mixer_strip_width (Wide)
232 , constructed (false)
233 , _playlist_selector (0)
235 , no_save_visual (false)
236 , _leftmost_sample (0)
237 , samples_per_pixel (2048)
238 , zoom_focus (ZoomFocusPlayhead)
239 , mouse_mode (MouseObject)
240 , pre_internal_grid_type (GridTypeBeat)
241 , pre_internal_snap_mode (SnapOff)
242 , internal_grid_type (GridTypeBeat)
243 , internal_snap_mode (SnapOff)
244 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
245 , _notebook_shrunk (false)
246 , location_marker_color (0)
247 , location_range_color (0)
248 , location_loop_color (0)
249 , location_punch_color (0)
250 , location_cd_marker_color (0)
252 , _show_marker_lines (false)
253 , clicked_axisview (0)
254 , clicked_routeview (0)
255 , clicked_regionview (0)
256 , clicked_selection (0)
257 , clicked_control_point (0)
258 , button_release_can_deselect (true)
259 , _mouse_changed_selection (false)
260 , region_edit_menu_split_item (0)
261 , region_edit_menu_split_multichannel_item (0)
262 , track_region_edit_playlist_menu (0)
263 , track_edit_playlist_submenu (0)
264 , track_selection_edit_playlist_submenu (0)
265 , _popup_region_menu_item (0)
267 , _track_canvas_viewport (0)
268 , within_track_canvas (false)
269 , _verbose_cursor (0)
273 , range_marker_group (0)
274 , transport_marker_group (0)
275 , cd_marker_group (0)
276 , _time_markers_group (0)
277 , hv_scroll_group (0)
279 , cursor_scroll_group (0)
280 , no_scroll_group (0)
281 , _trackview_group (0)
282 , _drag_motion_group (0)
283 , _canvas_drop_zone (0)
284 , no_ruler_shown_update (false)
285 , ruler_grabbed_widget (0)
287 , minsec_mark_interval (0)
288 , minsec_mark_modulo (0)
290 , timecode_ruler_scale (timecode_show_many_hours)
291 , timecode_mark_modulo (0)
292 , timecode_nmarks (0)
293 , _samples_ruler_interval (0)
294 , bbt_ruler_scale (bbt_show_many)
297 , bbt_bar_helper_on (0)
298 , bbt_accent_modulo (0)
303 , visible_timebars (0)
304 , editor_ruler_menu (0)
308 , range_marker_bar (0)
309 , transport_marker_bar (0)
311 , minsec_label (_("Mins:Secs"))
312 , bbt_label (_("Bars:Beats"))
313 , timecode_label (_("Timecode"))
314 , samples_label (_("Samples"))
315 , tempo_label (_("Tempo"))
316 , meter_label (_("Meter"))
317 , mark_label (_("Location Markers"))
318 , range_mark_label (_("Range Markers"))
319 , transport_mark_label (_("Loop/Punch Ranges"))
320 , cd_mark_label (_("CD Markers"))
321 , videotl_label (_("Video Timeline"))
324 , playhead_cursor (0)
325 , _region_boundary_cache_dirty (true)
326 , edit_packer (4, 4, true)
327 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
328 , horizontal_adjustment (0.0, 0.0, 1e16)
329 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
330 , controls_layout (unused_adjustment, vertical_adjustment)
331 , _scroll_callbacks (0)
332 , _visible_canvas_width (0)
333 , _visible_canvas_height (0)
334 , _full_canvas_height (0)
335 , edit_controls_left_menu (0)
336 , edit_controls_right_menu (0)
337 , visual_change_queued(false)
338 , _last_update_time (0)
339 , _err_screen_engine (0)
340 , cut_buffer_start (0)
341 , cut_buffer_length (0)
342 , button_bindings (0)
343 , last_paste_pos (-1)
346 , current_interthread_info (0)
347 , analysis_window (0)
348 , select_new_marker (false)
350 , scrubbing_direction (0)
351 , scrub_reversals (0)
352 , scrub_reverse_distance (0)
353 , have_pending_keyboard_selection (false)
354 , pending_keyboard_selection_start (0)
355 , _grid_type (GridTypeBeat)
356 , _snap_mode (SnapOff)
357 , ignore_gui_changes (false)
358 , _drags (new DragManager (this))
360 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
361 , _dragging_playhead (false)
362 , _dragging_edit_point (false)
363 , _follow_playhead (true)
364 , _stationary_playhead (false)
367 , global_rect_group (0)
368 , time_line_group (0)
369 , tempo_marker_menu (0)
370 , meter_marker_menu (0)
372 , range_marker_menu (0)
373 , transport_marker_menu (0)
374 , new_transport_marker_menu (0)
376 , marker_menu_item (0)
377 , bbt_beat_subdivision (4)
378 , _visible_track_count (-1)
379 , toolbar_selection_clock_table (2,3)
380 , automation_mode_button (_("mode"))
381 , selection (new Selection (this, true))
382 , cut_buffer (new Selection (this, false))
383 , _selection_memento (new SelectionMemento())
384 , _all_region_actions_sensitized (false)
385 , _ignore_region_action (false)
386 , _last_region_menu_was_main (false)
387 , _track_selection_change_without_scroll (false)
388 , _editor_track_selection_change_without_scroll (false)
389 , cd_marker_bar_drag_rect (0)
390 , range_bar_drag_rect (0)
391 , transport_bar_drag_rect (0)
392 , transport_bar_range_rect (0)
393 , transport_bar_preroll_rect (0)
394 , transport_bar_postroll_rect (0)
395 , transport_loop_range_rect (0)
396 , transport_punch_range_rect (0)
397 , transport_punchin_line (0)
398 , transport_punchout_line (0)
399 , transport_preroll_rect (0)
400 , transport_postroll_rect (0)
402 , rubberband_rect (0)
408 , autoscroll_horizontal_allowed (false)
409 , autoscroll_vertical_allowed (false)
411 , autoscroll_widget (0)
412 , show_gain_after_trim (false)
413 , selection_op_cmd_depth (0)
414 , selection_op_history_it (0)
415 , no_save_instant (false)
417 , current_mixer_strip (0)
418 , show_editor_mixer_when_tracks_arrive (false)
419 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
420 , current_stepping_trackview (0)
421 , last_track_height_step_timestamp (0)
423 , entered_regionview (0)
424 , clear_entered_track (false)
425 , _edit_point (EditAtMouse)
426 , meters_running (false)
428 , _have_idled (false)
429 , resize_idle_id (-1)
430 , _pending_resize_amount (0)
431 , _pending_resize_view (0)
432 , _pending_locate_request (false)
433 , _pending_initial_locate (false)
437 , layering_order_editor (0)
438 , _last_cut_copy_source_track (0)
439 , _region_selection_change_updates_region_list (true)
441 , _following_mixer_selection (false)
442 , _control_point_toggled_on_press (false)
443 , _stepping_axis_view (0)
444 , quantize_dialog (0)
445 , _main_menu_disabler (0)
446 , myactions (X_("editor"))
448 /* we are a singleton */
450 PublicEditor::_instance = this;
454 last_event_time.tv_sec = 0;
455 last_event_time.tv_usec = 0;
457 selection_op_history.clear();
460 grid_type_strings = I18N (_grid_type_strings);
461 zoom_focus_strings = I18N (_zoom_focus_strings);
462 edit_mode_strings = I18N (_edit_mode_strings);
463 edit_point_strings = I18N (_edit_point_strings);
464 #ifdef USE_RUBBERBAND
465 rb_opt_strings = I18N (_rb_opt_strings);
469 build_edit_mode_menu();
470 build_zoom_focus_menu();
471 build_track_count_menu();
472 build_grid_type_menu();
473 build_edit_point_menu();
475 location_marker_color = UIConfiguration::instance().color ("location marker");
476 location_range_color = UIConfiguration::instance().color ("location range");
477 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
478 location_loop_color = UIConfiguration::instance().color ("location loop");
479 location_punch_color = UIConfiguration::instance().color ("location punch");
481 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
483 TimeAxisView::setup_sizes ();
484 ArdourMarker::setup_sizes (timebar_height);
485 TempoCurve::setup_sizes (timebar_height);
487 bbt_label.set_name ("EditorRulerLabel");
488 bbt_label.set_size_request (-1, (int)timebar_height);
489 bbt_label.set_alignment (1.0, 0.5);
490 bbt_label.set_padding (5,0);
492 bbt_label.set_no_show_all();
493 minsec_label.set_name ("EditorRulerLabel");
494 minsec_label.set_size_request (-1, (int)timebar_height);
495 minsec_label.set_alignment (1.0, 0.5);
496 minsec_label.set_padding (5,0);
497 minsec_label.hide ();
498 minsec_label.set_no_show_all();
499 timecode_label.set_name ("EditorRulerLabel");
500 timecode_label.set_size_request (-1, (int)timebar_height);
501 timecode_label.set_alignment (1.0, 0.5);
502 timecode_label.set_padding (5,0);
503 timecode_label.hide ();
504 timecode_label.set_no_show_all();
505 samples_label.set_name ("EditorRulerLabel");
506 samples_label.set_size_request (-1, (int)timebar_height);
507 samples_label.set_alignment (1.0, 0.5);
508 samples_label.set_padding (5,0);
509 samples_label.hide ();
510 samples_label.set_no_show_all();
512 tempo_label.set_name ("EditorRulerLabel");
513 tempo_label.set_size_request (-1, (int)timebar_height);
514 tempo_label.set_alignment (1.0, 0.5);
515 tempo_label.set_padding (5,0);
517 tempo_label.set_no_show_all();
519 meter_label.set_name ("EditorRulerLabel");
520 meter_label.set_size_request (-1, (int)timebar_height);
521 meter_label.set_alignment (1.0, 0.5);
522 meter_label.set_padding (5,0);
524 meter_label.set_no_show_all();
526 if (Profile->get_trx()) {
527 mark_label.set_text (_("Markers"));
529 mark_label.set_name ("EditorRulerLabel");
530 mark_label.set_size_request (-1, (int)timebar_height);
531 mark_label.set_alignment (1.0, 0.5);
532 mark_label.set_padding (5,0);
534 mark_label.set_no_show_all();
536 cd_mark_label.set_name ("EditorRulerLabel");
537 cd_mark_label.set_size_request (-1, (int)timebar_height);
538 cd_mark_label.set_alignment (1.0, 0.5);
539 cd_mark_label.set_padding (5,0);
540 cd_mark_label.hide();
541 cd_mark_label.set_no_show_all();
543 videotl_bar_height = 4;
544 videotl_label.set_name ("EditorRulerLabel");
545 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
546 videotl_label.set_alignment (1.0, 0.5);
547 videotl_label.set_padding (5,0);
548 videotl_label.hide();
549 videotl_label.set_no_show_all();
551 range_mark_label.set_name ("EditorRulerLabel");
552 range_mark_label.set_size_request (-1, (int)timebar_height);
553 range_mark_label.set_alignment (1.0, 0.5);
554 range_mark_label.set_padding (5,0);
555 range_mark_label.hide();
556 range_mark_label.set_no_show_all();
558 transport_mark_label.set_name ("EditorRulerLabel");
559 transport_mark_label.set_size_request (-1, (int)timebar_height);
560 transport_mark_label.set_alignment (1.0, 0.5);
561 transport_mark_label.set_padding (5,0);
562 transport_mark_label.hide();
563 transport_mark_label.set_no_show_all();
565 initialize_canvas ();
567 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
569 _summary = new EditorSummary (this);
571 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
572 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
574 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
576 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
577 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
579 edit_controls_vbox.set_spacing (0);
580 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
581 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
583 HBox* h = manage (new HBox);
584 _group_tabs = new EditorGroupTabs (this);
585 if (!ARDOUR::Profile->get_trx()) {
586 h->pack_start (*_group_tabs, PACK_SHRINK);
588 h->pack_start (edit_controls_vbox);
589 controls_layout.add (*h);
591 controls_layout.set_name ("EditControlsBase");
592 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
593 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
594 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
596 _cursors = new MouseCursors;
597 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
598 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
600 /* Push default cursor to ever-present bottom of cursor stack. */
601 push_canvas_cursor(_cursors->grabber);
603 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
605 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
606 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
607 pad_line_1->set_outline_color (0xFF0000FF);
613 edit_packer.set_col_spacings (0);
614 edit_packer.set_row_spacings (0);
615 edit_packer.set_homogeneous (false);
616 edit_packer.set_border_width (0);
617 edit_packer.set_name ("EditorWindow");
619 time_bars_event_box.add (time_bars_vbox);
620 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
621 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
623 /* labels for the time bars */
624 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
626 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
628 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
630 bottom_hbox.set_border_width (2);
631 bottom_hbox.set_spacing (3);
633 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
635 _route_groups = new EditorRouteGroups (this);
636 _routes = new EditorRoutes (this);
637 _regions = new EditorRegions (this);
638 _snapshots = new EditorSnapshots (this);
639 _locations = new EditorLocations (this);
640 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
642 /* these are static location signals */
644 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
645 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
646 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
648 add_notebook_page (_("Regions"), _regions->widget ());
649 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
650 add_notebook_page (_("Snapshots"), _snapshots->widget ());
651 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
652 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
654 _the_notebook.set_show_tabs (true);
655 _the_notebook.set_scrollable (true);
656 _the_notebook.popup_disable ();
657 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
658 _the_notebook.show_all ();
660 _notebook_shrunk = false;
663 /* Pick up some settings we need to cache, early */
665 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
668 settings->get_property ("notebook-shrunk", _notebook_shrunk);
671 editor_summary_pane.set_check_divider_position (true);
672 editor_summary_pane.add (edit_packer);
674 Button* summary_arrow_left = manage (new Button);
675 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
676 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
677 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
679 Button* summary_arrow_right = manage (new Button);
680 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
681 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
682 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
684 VBox* summary_arrows_left = manage (new VBox);
685 summary_arrows_left->pack_start (*summary_arrow_left);
687 VBox* summary_arrows_right = manage (new VBox);
688 summary_arrows_right->pack_start (*summary_arrow_right);
690 Frame* summary_sample = manage (new Frame);
691 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
693 summary_sample->add (*_summary);
694 summary_sample->show ();
696 _summary_hbox.pack_start (*summary_arrows_left, false, false);
697 _summary_hbox.pack_start (*summary_sample, true, true);
698 _summary_hbox.pack_start (*summary_arrows_right, false, false);
700 if (!ARDOUR::Profile->get_trx()) {
701 editor_summary_pane.add (_summary_hbox);
704 edit_pane.set_check_divider_position (true);
705 edit_pane.add (editor_summary_pane);
706 if (!ARDOUR::Profile->get_trx()) {
707 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
708 _editor_list_vbox.pack_start (_the_notebook);
709 edit_pane.add (_editor_list_vbox);
710 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
713 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
714 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
717 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
718 /* initial allocation is 90% to canvas, 10% to notebook */
721 edit_pane.set_divider (0, fract);
723 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
724 /* initial allocation is 90% to canvas, 10% to summary */
727 editor_summary_pane.set_divider (0, fract);
729 global_vpacker.set_spacing (2);
730 global_vpacker.set_border_width (0);
732 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
734 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
735 ebox->set_name("EditorWindow");
736 ebox->add (toolbar_hbox);
738 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
739 epane_box->set_name("EditorWindow");
740 epane_box->add (edit_pane);
742 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
743 epane_box2->set_name("EditorWindow");
744 epane_box2->add (global_vpacker);
746 global_vpacker.pack_start (*ebox, false, false);
747 global_vpacker.pack_start (*epane_box, true, true);
748 global_hpacker.pack_start (*epane_box2, true, true);
750 /* need to show the "contents" widget so that notebook will show if tab is switched to
753 global_hpacker.show ();
755 /* register actions now so that set_state() can find them and set toggles/checks etc */
762 _playlist_selector = new PlaylistSelector();
763 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
765 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
769 nudge_forward_button.set_name ("nudge button");
770 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
772 nudge_backward_button.set_name ("nudge button");
773 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
775 fade_context_menu.set_name ("ArdourContextMenu");
777 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
779 /* allow external control surfaces/protocols to do various things */
781 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
782 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
783 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
784 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
785 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
786 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
787 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
788 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
789 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
790 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
791 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
792 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
793 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
794 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
796 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
797 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
798 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
799 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
800 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
802 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
806 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
808 /* problematic: has to return a value and thus cannot be x-thread */
810 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
812 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
813 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
815 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
817 _ignore_region_action = false;
818 _last_region_menu_was_main = false;
819 _popup_region_menu_item = 0;
821 _show_marker_lines = false;
823 /* Button bindings */
825 button_bindings = new Bindings ("editor-mouse");
827 XMLNode* node = button_settings();
829 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
830 button_bindings->load_operation (**i);
836 /* grab current parameter state */
837 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
838 UIConfiguration::instance().map_parameters (pc);
840 setup_fade_images ();
842 set_grid_to (GridTypeNone);
849 delete button_bindings;
851 delete _route_groups;
852 delete _track_canvas_viewport;
855 delete _verbose_cursor;
856 delete quantize_dialog;
862 delete _playlist_selector;
863 delete _time_info_box;
868 LuaInstance::destroy_instance ();
870 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
873 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
876 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
882 Editor::button_settings () const
884 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
885 XMLNode* node = find_named_node (*settings, X_("Buttons"));
888 node = new XMLNode (X_("Buttons"));
895 Editor::get_smart_mode () const
897 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
901 Editor::catch_vanishing_regionview (RegionView *rv)
903 /* note: the selection will take care of the vanishing
904 audioregionview by itself.
907 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
911 if (clicked_regionview == rv) {
912 clicked_regionview = 0;
915 if (entered_regionview == rv) {
916 set_entered_regionview (0);
919 if (!_all_region_actions_sensitized) {
920 sensitize_all_region_actions (true);
925 Editor::set_entered_regionview (RegionView* rv)
927 if (rv == entered_regionview) {
931 if (entered_regionview) {
932 entered_regionview->exited ();
935 entered_regionview = rv;
937 if (entered_regionview != 0) {
938 entered_regionview->entered ();
941 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
942 /* This RegionView entry might have changed what region actions
943 are allowed, so sensitize them all in case a key is pressed.
945 sensitize_all_region_actions (true);
950 Editor::set_entered_track (TimeAxisView* tav)
953 entered_track->exited ();
959 entered_track->entered ();
964 Editor::instant_save ()
966 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
971 _session->add_instant_xml(get_state());
973 Config->add_instant_xml(get_state());
978 Editor::control_vertical_zoom_in_all ()
980 tav_zoom_smooth (false, true);
984 Editor::control_vertical_zoom_out_all ()
986 tav_zoom_smooth (true, true);
990 Editor::control_vertical_zoom_in_selected ()
992 tav_zoom_smooth (false, false);
996 Editor::control_vertical_zoom_out_selected ()
998 tav_zoom_smooth (true, false);
1002 Editor::control_view (uint32_t view)
1004 goto_visual_state (view);
1008 Editor::control_unselect ()
1010 selection->clear_tracks ();
1014 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1016 TimeAxisView* tav = time_axis_view_from_stripable (s);
1020 case Selection::Add:
1021 selection->add (tav);
1023 case Selection::Toggle:
1024 selection->toggle (tav);
1026 case Selection::Extend:
1028 case Selection::Set:
1029 selection->set (tav);
1033 selection->clear_tracks ();
1038 Editor::control_step_tracks_up ()
1040 scroll_tracks_up_line ();
1044 Editor::control_step_tracks_down ()
1046 scroll_tracks_down_line ();
1050 Editor::control_scroll (float fraction)
1052 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1058 double step = fraction * current_page_samples();
1061 _control_scroll_target is an optional<T>
1063 it acts like a pointer to an samplepos_t, with
1064 a operator conversion to boolean to check
1065 that it has a value could possibly use
1066 playhead_cursor->current_sample to store the
1067 value and a boolean in the class to know
1068 when it's out of date
1071 if (!_control_scroll_target) {
1072 _control_scroll_target = _session->transport_sample();
1073 _dragging_playhead = true;
1076 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1077 *_control_scroll_target = 0;
1078 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1079 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1081 *_control_scroll_target += (samplepos_t) trunc (step);
1084 /* move visuals, we'll catch up with it later */
1086 playhead_cursor->set_position (*_control_scroll_target);
1087 UpdateAllTransportClocks (*_control_scroll_target);
1089 if (*_control_scroll_target > (current_page_samples() / 2)) {
1090 /* try to center PH in window */
1091 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1097 Now we do a timeout to actually bring the session to the right place
1098 according to the playhead. This is to avoid reading disk buffers on every
1099 call to control_scroll, which is driven by ScrollTimeline and therefore
1100 probably by a control surface wheel which can generate lots of events.
1102 /* cancel the existing timeout */
1104 control_scroll_connection.disconnect ();
1106 /* add the next timeout */
1108 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1112 Editor::deferred_control_scroll (samplepos_t /*target*/)
1114 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1115 // reset for next stream
1116 _control_scroll_target = boost::none;
1117 _dragging_playhead = false;
1122 Editor::access_action (const std::string& action_group, const std::string& action_item)
1128 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1131 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1139 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1141 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1145 Editor::on_realize ()
1149 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1150 start_lock_event_timing ();
1155 Editor::start_lock_event_timing ()
1157 /* check if we should lock the GUI every 30 seconds */
1159 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1163 Editor::generic_event_handler (GdkEvent* ev)
1166 case GDK_BUTTON_PRESS:
1167 case GDK_BUTTON_RELEASE:
1168 case GDK_MOTION_NOTIFY:
1170 case GDK_KEY_RELEASE:
1171 if (contents().is_mapped()) {
1172 gettimeofday (&last_event_time, 0);
1176 case GDK_LEAVE_NOTIFY:
1177 switch (ev->crossing.detail) {
1178 case GDK_NOTIFY_UNKNOWN:
1179 case GDK_NOTIFY_INFERIOR:
1180 case GDK_NOTIFY_ANCESTOR:
1182 case GDK_NOTIFY_VIRTUAL:
1183 case GDK_NOTIFY_NONLINEAR:
1184 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1185 /* leaving window, so reset focus, thus ending any and
1186 all text entry operations.
1188 ARDOUR_UI::instance()->reset_focus (&contents());
1201 Editor::lock_timeout_callback ()
1203 struct timeval now, delta;
1205 gettimeofday (&now, 0);
1207 timersub (&now, &last_event_time, &delta);
1209 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1211 /* don't call again. Returning false will effectively
1212 disconnect us from the timer callback.
1214 unlock() will call start_lock_event_timing() to get things
1224 Editor::map_position_change (samplepos_t sample)
1226 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1228 if (_session == 0) {
1232 if (_follow_playhead) {
1233 center_screen (sample);
1236 playhead_cursor->set_position (sample);
1240 Editor::center_screen (samplepos_t sample)
1242 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1244 /* if we're off the page, then scroll.
1247 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1248 center_screen_internal (sample, page);
1253 Editor::center_screen_internal (samplepos_t sample, float page)
1257 if (sample > page) {
1258 sample -= (samplepos_t) page;
1263 reset_x_origin (sample);
1268 Editor::update_title ()
1270 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1272 if (!own_window()) {
1277 bool dirty = _session->dirty();
1279 string session_name;
1281 if (_session->snap_name() != _session->name()) {
1282 session_name = _session->snap_name();
1284 session_name = _session->name();
1288 session_name = "*" + session_name;
1291 WindowTitle title(session_name);
1292 title += S_("Window|Editor");
1293 title += Glib::get_application_name();
1294 own_window()->set_title (title.get_string());
1296 /* ::session_going_away() will have taken care of it */
1301 Editor::set_session (Session *t)
1303 SessionHandlePtr::set_session (t);
1309 //initialize _leftmost_sample to the extents of the session
1310 //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample before the visible state has been loaded from instant.xml
1311 _leftmost_sample = session_gui_extents().first;
1313 _playlist_selector->set_session (_session);
1314 nudge_clock->set_session (_session);
1315 _summary->set_session (_session);
1316 _group_tabs->set_session (_session);
1317 _route_groups->set_session (_session);
1318 _regions->set_session (_session);
1319 _snapshots->set_session (_session);
1320 _routes->set_session (_session);
1321 _locations->set_session (_session);
1322 _time_info_box->set_session (_session);
1324 if (rhythm_ferret) {
1325 rhythm_ferret->set_session (_session);
1328 if (analysis_window) {
1329 analysis_window->set_session (_session);
1333 sfbrowser->set_session (_session);
1336 compute_fixed_ruler_scale ();
1338 /* Make sure we have auto loop and auto punch ranges */
1340 Location* loc = _session->locations()->auto_loop_location();
1342 loc->set_name (_("Loop"));
1345 loc = _session->locations()->auto_punch_location();
1348 loc->set_name (_("Punch"));
1351 refresh_location_display ();
1353 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1354 the selected Marker; this needs the LocationMarker list to be available.
1356 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1357 set_state (*node, Stateful::loading_state_version);
1359 /* catch up on selection state, etc. */
1362 sc.add (Properties::selected);
1363 presentation_info_changed (sc);
1365 /* catch up with the playhead */
1367 _session->request_locate (playhead_cursor->current_sample ());
1368 _pending_initial_locate = true;
1372 /* These signals can all be emitted by a non-GUI thread. Therefore the
1373 handlers for them must not attempt to directly interact with the GUI,
1374 but use PBD::Signal<T>::connect() which accepts an event loop
1375 ("context") where the handler will be asked to run.
1378 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1379 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1380 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1381 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1382 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1383 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1384 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1385 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1386 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1387 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1388 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1389 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1390 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1391 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1392 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1393 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1395 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1396 playhead_cursor->show ();
1398 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1399 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1400 snapped_cursor->show ();
1402 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1403 Config->map_parameters (pc);
1404 _session->config.map_parameters (pc);
1406 restore_ruler_visibility ();
1407 //tempo_map_changed (PropertyChange (0));
1408 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1410 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1411 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1414 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1415 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1418 /* register for undo history */
1419 _session->register_with_memento_command_factory(id(), this);
1420 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1422 LuaInstance::instance()->set_session(_session);
1424 start_updating_meters ();
1428 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1430 using namespace Menu_Helpers;
1432 void (Editor::*emf)(FadeShape);
1433 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1436 images = &_xfade_in_images;
1437 emf = &Editor::set_fade_in_shape;
1439 images = &_xfade_out_images;
1440 emf = &Editor::set_fade_out_shape;
1445 _("Linear (for highly correlated material)"),
1446 *(*images)[FadeLinear],
1447 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1451 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1455 _("Constant power"),
1456 *(*images)[FadeConstantPower],
1457 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1460 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1465 *(*images)[FadeSymmetric],
1466 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *(*images)[FadeSlow],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *(*images)[FadeFast],
1485 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 /** Pop up a context menu for when the user clicks on a start crossfade */
1493 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1495 using namespace Menu_Helpers;
1496 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1501 MenuList& items (xfade_in_context_menu.items());
1504 if (arv->audio_region()->fade_in_active()) {
1505 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1507 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1510 items.push_back (SeparatorElem());
1511 fill_xfade_menu (items, true);
1513 xfade_in_context_menu.popup (button, time);
1516 /** Pop up a context menu for when the user clicks on an end crossfade */
1518 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1520 using namespace Menu_Helpers;
1521 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1526 MenuList& items (xfade_out_context_menu.items());
1529 if (arv->audio_region()->fade_out_active()) {
1530 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1532 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1535 items.push_back (SeparatorElem());
1536 fill_xfade_menu (items, false);
1538 xfade_out_context_menu.popup (button, time);
1542 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1544 using namespace Menu_Helpers;
1545 Menu* (Editor::*build_menu_function)();
1548 switch (item_type) {
1550 case RegionViewName:
1551 case RegionViewNameHighlight:
1552 case LeftFrameHandle:
1553 case RightFrameHandle:
1554 if (with_selection) {
1555 build_menu_function = &Editor::build_track_selection_context_menu;
1557 build_menu_function = &Editor::build_track_region_context_menu;
1562 if (with_selection) {
1563 build_menu_function = &Editor::build_track_selection_context_menu;
1565 build_menu_function = &Editor::build_track_context_menu;
1570 if (clicked_routeview->track()) {
1571 build_menu_function = &Editor::build_track_context_menu;
1573 build_menu_function = &Editor::build_track_bus_context_menu;
1578 /* probably shouldn't happen but if it does, we don't care */
1582 menu = (this->*build_menu_function)();
1583 menu->set_name ("ArdourContextMenu");
1585 /* now handle specific situations */
1587 switch (item_type) {
1589 case RegionViewName:
1590 case RegionViewNameHighlight:
1591 case LeftFrameHandle:
1592 case RightFrameHandle:
1593 if (!with_selection) {
1594 if (region_edit_menu_split_item) {
1595 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1596 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1598 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1601 if (region_edit_menu_split_multichannel_item) {
1602 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1603 region_edit_menu_split_multichannel_item->set_sensitive (true);
1605 region_edit_menu_split_multichannel_item->set_sensitive (false);
1618 /* probably shouldn't happen but if it does, we don't care */
1622 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1624 /* Bounce to disk */
1626 using namespace Menu_Helpers;
1627 MenuList& edit_items = menu->items();
1629 edit_items.push_back (SeparatorElem());
1631 switch (clicked_routeview->audio_track()->freeze_state()) {
1632 case AudioTrack::NoFreeze:
1633 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1636 case AudioTrack::Frozen:
1637 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1640 case AudioTrack::UnFrozen:
1641 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1647 if (item_type == StreamItem && clicked_routeview) {
1648 clicked_routeview->build_underlay_menu(menu);
1651 /* When the region menu is opened, we setup the actions so that they look right
1654 sensitize_the_right_region_actions (false);
1655 _last_region_menu_was_main = false;
1657 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1658 menu->popup (button, time);
1662 Editor::build_track_context_menu ()
1664 using namespace Menu_Helpers;
1666 MenuList& edit_items = track_context_menu.items();
1669 add_dstream_context_items (edit_items);
1670 return &track_context_menu;
1674 Editor::build_track_bus_context_menu ()
1676 using namespace Menu_Helpers;
1678 MenuList& edit_items = track_context_menu.items();
1681 add_bus_context_items (edit_items);
1682 return &track_context_menu;
1686 Editor::build_track_region_context_menu ()
1688 using namespace Menu_Helpers;
1689 MenuList& edit_items = track_region_context_menu.items();
1692 /* we've just cleared the track region context menu, so the menu that these
1693 two items were on will have disappeared; stop them dangling.
1695 region_edit_menu_split_item = 0;
1696 region_edit_menu_split_multichannel_item = 0;
1698 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1701 boost::shared_ptr<Track> tr;
1702 boost::shared_ptr<Playlist> pl;
1704 if ((tr = rtv->track())) {
1705 add_region_context_items (edit_items, tr);
1709 add_dstream_context_items (edit_items);
1711 return &track_region_context_menu;
1715 Editor::loudness_analyze_region_selection ()
1720 Selection& s (PublicEditor::instance ().get_selection ());
1721 RegionSelection ars = s.regions;
1722 ARDOUR::AnalysisGraph ag (_session);
1723 samplecnt_t total_work = 0;
1725 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1726 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1730 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1733 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1734 total_work += arv->region ()->length ();
1737 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1739 ag.set_total_samples (total_work);
1740 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1743 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1744 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1748 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1752 ag.analyze_region (ar);
1755 if (!ag.canceled ()) {
1756 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1762 Editor::loudness_analyze_range_selection ()
1767 Selection& s (PublicEditor::instance ().get_selection ());
1768 TimeSelection ts = s.time;
1769 ARDOUR::AnalysisGraph ag (_session);
1770 samplecnt_t total_work = 0;
1772 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1773 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1777 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1781 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1782 total_work += j->length ();
1786 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1788 ag.set_total_samples (total_work);
1789 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1792 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1793 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1797 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1801 ag.analyze_range (rui->route (), pl, ts);
1804 if (!ag.canceled ()) {
1805 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1811 Editor::spectral_analyze_region_selection ()
1813 if (analysis_window == 0) {
1814 analysis_window = new AnalysisWindow();
1817 analysis_window->set_session(_session);
1819 analysis_window->show_all();
1822 analysis_window->set_regionmode();
1823 analysis_window->analyze();
1825 analysis_window->present();
1829 Editor::spectral_analyze_range_selection()
1831 if (analysis_window == 0) {
1832 analysis_window = new AnalysisWindow();
1835 analysis_window->set_session(_session);
1837 analysis_window->show_all();
1840 analysis_window->set_rangemode();
1841 analysis_window->analyze();
1843 analysis_window->present();
1847 Editor::build_track_selection_context_menu ()
1849 using namespace Menu_Helpers;
1850 MenuList& edit_items = track_selection_context_menu.items();
1851 edit_items.clear ();
1853 add_selection_context_items (edit_items);
1854 // edit_items.push_back (SeparatorElem());
1855 // add_dstream_context_items (edit_items);
1857 return &track_selection_context_menu;
1861 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1863 using namespace Menu_Helpers;
1865 /* OK, stick the region submenu at the top of the list, and then add
1869 RegionSelection rs = get_regions_from_selection_and_entered ();
1871 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1873 if (_popup_region_menu_item == 0) {
1874 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1875 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1876 _popup_region_menu_item->show ();
1878 _popup_region_menu_item->set_label (menu_item_name);
1881 /* No layering allowed in later is higher layering model */
1882 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1883 if (act && Config->get_layer_model() == LaterHigher) {
1884 act->set_sensitive (false);
1886 act->set_sensitive (true);
1889 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1891 edit_items.push_back (*_popup_region_menu_item);
1892 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1893 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1895 edit_items.push_back (SeparatorElem());
1898 /** Add context menu items relevant to selection ranges.
1899 * @param edit_items List to add the items to.
1902 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1904 using namespace Menu_Helpers;
1906 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1907 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1914 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1916 edit_items.push_back (SeparatorElem());
1918 edit_items.push_back (
1920 _("Move Range Start to Previous Region Boundary"),
1921 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1925 edit_items.push_back (
1927 _("Move Range Start to Next Region Boundary"),
1928 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1932 edit_items.push_back (
1934 _("Move Range End to Previous Region Boundary"),
1935 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1939 edit_items.push_back (
1941 _("Move Range End to Next Region Boundary"),
1942 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1946 edit_items.push_back (SeparatorElem());
1947 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1948 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1950 edit_items.push_back (SeparatorElem());
1951 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1955 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1956 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1958 edit_items.push_back (SeparatorElem());
1959 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1961 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1963 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1967 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1968 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1969 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1970 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1971 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1972 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1978 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1980 using namespace Menu_Helpers;
1984 Menu *play_menu = manage (new Menu);
1985 MenuList& play_items = play_menu->items();
1986 play_menu->set_name ("ArdourContextMenu");
1988 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1989 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1990 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1991 play_items.push_back (SeparatorElem());
1992 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1994 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1998 Menu *select_menu = manage (new Menu);
1999 MenuList& select_items = select_menu->items();
2000 select_menu->set_name ("ArdourContextMenu");
2002 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2003 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2004 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2005 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2006 select_items.push_back (SeparatorElem());
2007 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2008 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2009 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2010 select_items.push_back (SeparatorElem());
2011 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2012 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2013 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2014 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2015 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2016 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2017 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2019 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2023 Menu *cutnpaste_menu = manage (new Menu);
2024 MenuList& cutnpaste_items = cutnpaste_menu->items();
2025 cutnpaste_menu->set_name ("ArdourContextMenu");
2027 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2028 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2029 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2031 cutnpaste_items.push_back (SeparatorElem());
2033 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2034 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2036 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2038 /* Adding new material */
2040 edit_items.push_back (SeparatorElem());
2041 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2042 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2046 Menu *nudge_menu = manage (new Menu());
2047 MenuList& nudge_items = nudge_menu->items();
2048 nudge_menu->set_name ("ArdourContextMenu");
2050 edit_items.push_back (SeparatorElem());
2051 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2052 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2054 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2056 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2060 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2062 using namespace Menu_Helpers;
2066 Menu *play_menu = manage (new Menu);
2067 MenuList& play_items = play_menu->items();
2068 play_menu->set_name ("ArdourContextMenu");
2070 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2071 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2072 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2076 Menu *select_menu = manage (new Menu);
2077 MenuList& select_items = select_menu->items();
2078 select_menu->set_name ("ArdourContextMenu");
2080 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2081 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2082 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2083 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2084 select_items.push_back (SeparatorElem());
2085 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2086 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2087 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2088 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2090 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2094 Menu *cutnpaste_menu = manage (new Menu);
2095 MenuList& cutnpaste_items = cutnpaste_menu->items();
2096 cutnpaste_menu->set_name ("ArdourContextMenu");
2098 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2099 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2100 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2102 Menu *nudge_menu = manage (new Menu());
2103 MenuList& nudge_items = nudge_menu->items();
2104 nudge_menu->set_name ("ArdourContextMenu");
2106 edit_items.push_back (SeparatorElem());
2107 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2108 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2109 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2110 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2112 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2116 Editor::grid_type() const
2122 Editor::grid_musical() const
2124 switch (_grid_type) {
2125 case GridTypeBeatDiv32:
2126 case GridTypeBeatDiv28:
2127 case GridTypeBeatDiv24:
2128 case GridTypeBeatDiv20:
2129 case GridTypeBeatDiv16:
2130 case GridTypeBeatDiv14:
2131 case GridTypeBeatDiv12:
2132 case GridTypeBeatDiv10:
2133 case GridTypeBeatDiv8:
2134 case GridTypeBeatDiv7:
2135 case GridTypeBeatDiv6:
2136 case GridTypeBeatDiv5:
2137 case GridTypeBeatDiv4:
2138 case GridTypeBeatDiv3:
2139 case GridTypeBeatDiv2:
2145 case GridTypeMinSec:
2146 case GridTypeSamples:
2153 Editor::grid_nonmusical() const
2155 switch (_grid_type) {
2157 case GridTypeMinSec:
2158 case GridTypeSamples:
2160 case GridTypeBeatDiv32:
2161 case GridTypeBeatDiv28:
2162 case GridTypeBeatDiv24:
2163 case GridTypeBeatDiv20:
2164 case GridTypeBeatDiv16:
2165 case GridTypeBeatDiv14:
2166 case GridTypeBeatDiv12:
2167 case GridTypeBeatDiv10:
2168 case GridTypeBeatDiv8:
2169 case GridTypeBeatDiv7:
2170 case GridTypeBeatDiv6:
2171 case GridTypeBeatDiv5:
2172 case GridTypeBeatDiv4:
2173 case GridTypeBeatDiv3:
2174 case GridTypeBeatDiv2:
2183 Editor::snap_mode() const
2189 Editor::set_grid_to (GridType gt)
2191 if (_grid_type == gt) { //already set
2195 unsigned int grid_ind = (unsigned int)gt;
2197 if (internal_editing()) {
2198 internal_grid_type = gt;
2200 pre_internal_grid_type = gt;
2205 if (grid_ind > grid_type_strings.size() - 1) {
2207 _grid_type = (GridType)grid_ind;
2210 string str = grid_type_strings[grid_ind];
2212 if (str != grid_type_selector.get_text()) {
2213 grid_type_selector.set_text (str);
2216 //show appropriate rulers for this grid setting. (ToDo: perhaps make this optional)
2217 //Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2218 if ( grid_musical() ) {
2219 ruler_tempo_action->set_active(true);
2220 ruler_meter_action->set_active(true);
2222 ruler_bbt_action->set_active(true);
2223 ruler_timecode_action->set_active(false);
2224 ruler_minsec_action->set_active(false);
2225 ruler_samples_action->set_active(false);
2226 } else if (_grid_type == GridTypeSmpte ) {
2227 ruler_tempo_action->set_active(false);
2228 ruler_meter_action->set_active(false);
2230 ruler_bbt_action->set_active(false);
2231 ruler_timecode_action->set_active(true);
2232 ruler_minsec_action->set_active(false);
2233 ruler_samples_action->set_active(false);
2234 } else if (_grid_type == GridTypeMinSec ) {
2235 ruler_tempo_action->set_active(false);
2236 ruler_meter_action->set_active(false);
2238 ruler_bbt_action->set_active(false);
2239 ruler_timecode_action->set_active(false);
2240 ruler_minsec_action->set_active(true);
2241 ruler_samples_action->set_active(false);
2242 } else if (_grid_type == GridTypeSamples ) {
2243 ruler_tempo_action->set_active(false);
2244 ruler_meter_action->set_active(false);
2246 ruler_bbt_action->set_active(false);
2247 ruler_timecode_action->set_active(false);
2248 ruler_minsec_action->set_active(false);
2249 ruler_samples_action->set_active(true);
2254 if ( grid_musical() ) {
2255 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2256 update_tempo_based_rulers ();
2259 mark_region_boundary_cache_dirty ();
2261 redisplay_grid (false);
2263 SnapChanged (); /* EMIT SIGNAL */
2267 Editor::set_snap_mode (SnapMode mode)
2269 if (internal_editing()) {
2270 internal_snap_mode = mode;
2272 pre_internal_snap_mode = mode;
2277 if (_snap_mode == SnapOff ) {
2278 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2280 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2287 Editor::set_edit_point_preference (EditPoint ep, bool force)
2289 bool changed = (_edit_point != ep);
2292 if (Profile->get_mixbus())
2293 if (ep == EditAtSelectedMarker)
2294 ep = EditAtPlayhead;
2296 string str = edit_point_strings[(int)ep];
2297 if (str != edit_point_selector.get_text ()) {
2298 edit_point_selector.set_text (str);
2301 update_all_enter_cursors();
2303 if (!force && !changed) {
2307 const char* action=NULL;
2309 switch (_edit_point) {
2310 case EditAtPlayhead:
2311 action = "edit-at-playhead";
2313 case EditAtSelectedMarker:
2314 action = "edit-at-marker";
2317 action = "edit-at-mouse";
2321 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2323 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2327 bool in_track_canvas;
2329 if (!mouse_sample (foo, in_track_canvas)) {
2330 in_track_canvas = false;
2333 reset_canvas_action_sensitivity (in_track_canvas);
2334 sensitize_the_right_region_actions (false);
2340 Editor::set_state (const XMLNode& node, int version)
2343 PBD::Unwinder<bool> nsi (no_save_instant, true);
2346 Tabbable::set_state (node, version);
2349 if (_session && node.get_property ("playhead", ph_pos)) {
2351 playhead_cursor->set_position (ph_pos);
2353 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2354 playhead_cursor->set_position (0);
2357 playhead_cursor->set_position (0);
2360 node.get_property ("mixer-width", editor_mixer_strip_width);
2362 node.get_property ("zoom-focus", zoom_focus);
2363 zoom_focus_selection_done (zoom_focus);
2366 if (node.get_property ("zoom", z)) {
2367 /* older versions of ardour used floating point samples_per_pixel */
2368 reset_zoom (llrintf (z));
2370 reset_zoom (samples_per_pixel);
2374 if (node.get_property ("visible-track-count", cnt)) {
2375 set_visible_track_count (cnt);
2379 if (!node.get_property ("grid-type", grid_type)) {
2380 grid_type = _grid_type;
2382 set_grid_to (grid_type);
2385 if (node.get_property ("snap-mode", sm)) {
2386 snap_mode_selection_done(sm);
2387 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2388 * snap_mode_selection_done() will only mark an already active item as active
2389 * which does not trigger set_text().
2393 set_snap_mode (_snap_mode);
2396 node.get_property ("internal-grid-type", internal_grid_type);
2397 node.get_property ("internal-snap-mode", internal_snap_mode);
2398 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2399 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2402 if (node.get_property ("mouse-mode", mm_str)) {
2403 MouseMode m = str2mousemode(mm_str);
2404 set_mouse_mode (m, true);
2406 set_mouse_mode (MouseObject, true);
2410 if (node.get_property ("left-frame", lf_pos)) {
2414 reset_x_origin (lf_pos);
2418 if (node.get_property ("y-origin", y_origin)) {
2419 reset_y_origin (y_origin);
2422 if (node.get_property ("join-object-range", yn)) {
2423 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2425 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2426 tact->set_active (!yn);
2427 tact->set_active (yn);
2429 set_mouse_mode(mouse_mode, true);
2433 if (node.get_property ("edit-point", ep)) {
2434 set_edit_point_preference (ep, true);
2436 set_edit_point_preference (_edit_point);
2439 if (node.get_property ("follow-playhead", yn)) {
2440 set_follow_playhead (yn);
2443 if (node.get_property ("stationary-playhead", yn)) {
2444 set_stationary_playhead (yn);
2447 RegionListSortType sort_type;
2448 if (node.get_property ("region-list-sort-type", sort_type)) {
2449 _regions->reset_sort_type (sort_type, true);
2452 if (node.get_property ("show-editor-mixer", yn)) {
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2457 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 /* do it twice to force the change */
2461 tact->set_active (!yn);
2462 tact->set_active (yn);
2465 if (node.get_property ("show-editor-list", yn)) {
2467 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2470 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2472 /* do it twice to force the change */
2474 tact->set_active (!yn);
2475 tact->set_active (yn);
2479 if (node.get_property (X_("editor-list-page"), el_page)) {
2480 _the_notebook.set_current_page (el_page);
2483 if (node.get_property (X_("show-marker-lines"), yn)) {
2484 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2486 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2488 tact->set_active (!yn);
2489 tact->set_active (yn);
2492 XMLNodeList children = node.children ();
2493 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2494 selection->set_state (**i, Stateful::current_state_version);
2495 _regions->set_state (**i);
2496 _locations->set_state (**i);
2499 if (node.get_property ("maximised", yn)) {
2500 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2502 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503 bool fs = tact && tact->get_active();
2505 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2509 samplepos_t nudge_clock_value;
2510 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2511 nudge_clock->set (nudge_clock_value);
2513 nudge_clock->set_mode (AudioClock::Timecode);
2514 nudge_clock->set (_session->sample_rate() * 5, true);
2519 * Not all properties may have been in XML, but
2520 * those that are linked to a private variable may need changing
2524 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2525 yn = _follow_playhead;
2527 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2528 if (tact->get_active() != yn) {
2529 tact->set_active (yn);
2533 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2534 yn = _stationary_playhead;
2536 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2537 if (tact->get_active() != yn) {
2538 tact->set_active (yn);
2543 return LuaInstance::instance()->set_state(node);
2547 Editor::get_state ()
2549 XMLNode* node = new XMLNode (X_("Editor"));
2551 node->set_property ("id", id().to_s ());
2553 node->add_child_nocopy (Tabbable::get_state());
2555 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2556 node->set_property("notebook-shrunk", _notebook_shrunk);
2557 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2559 maybe_add_mixer_strip_width (*node);
2561 node->set_property ("zoom-focus", zoom_focus);
2563 node->set_property ("zoom", samples_per_pixel);
2564 node->set_property ("grid-type", _grid_type);
2565 node->set_property ("snap-mode", _snap_mode);
2566 node->set_property ("internal-grid-type", internal_grid_type);
2567 node->set_property ("internal-snap-mode", internal_snap_mode);
2568 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2569 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2570 node->set_property ("edit-point", _edit_point);
2571 node->set_property ("visible-track-count", _visible_track_count);
2573 node->set_property ("playhead", playhead_cursor->current_sample ());
2574 node->set_property ("left-frame", _leftmost_sample);
2575 node->set_property ("y-origin", vertical_adjustment.get_value ());
2577 node->set_property ("maximised", _maximised);
2578 node->set_property ("follow-playhead", _follow_playhead);
2579 node->set_property ("stationary-playhead", _stationary_playhead);
2580 node->set_property ("region-list-sort-type", _regions->sort_type ());
2581 node->set_property ("mouse-mode", mouse_mode);
2582 node->set_property ("join-object-range", smart_mode_action->get_active ());
2584 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2586 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2587 node->set_property (X_("show-editor-mixer"), tact->get_active());
2590 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2592 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2593 node->set_property (X_("show-editor-list"), tact->get_active());
2596 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2598 if (button_bindings) {
2599 XMLNode* bb = new XMLNode (X_("Buttons"));
2600 button_bindings->save (*bb);
2601 node->add_child_nocopy (*bb);
2604 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2606 node->add_child_nocopy (selection->get_state ());
2607 node->add_child_nocopy (_regions->get_state ());
2609 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2611 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2612 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2613 node->add_child_nocopy (_locations->get_state ());
2618 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2619 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2621 * @return pair: TimeAxisView that y is over, layer index.
2623 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2624 * in stacked or expanded region display mode, otherwise 0.
2626 std::pair<TimeAxisView *, double>
2627 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2629 if (!trackview_relative_offset) {
2630 y -= _trackview_group->canvas_origin().y;
2634 return std::make_pair ( (TimeAxisView *) 0, 0);
2637 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2639 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2646 return std::make_pair ( (TimeAxisView *) 0, 0);
2650 Editor::set_snapped_cursor_position (samplepos_t pos)
2652 if ( _edit_point == EditAtMouse ) {
2653 snapped_cursor->set_position(pos);
2658 /** Snap a position to the grid, if appropriate, taking into account current
2659 * grid settings and also the state of any snap modifier keys that may be pressed.
2660 * @param start Position to snap.
2661 * @param event Event to get current key modifier information from, or 0.
2664 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2666 if (!_session || !event) {
2670 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2671 if (_snap_mode == SnapOff) {
2672 snap_to_internal (start, direction, pref, for_mark);
2674 start.set (start.sample, 0);
2677 if (_snap_mode != SnapOff) {
2678 snap_to_internal (start, direction, pref, for_mark);
2679 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2680 /* SnapOff, but we pressed the snap_delta modifier */
2681 snap_to_internal (start, direction, pref, for_mark);
2683 start.set (start.sample, 0);
2689 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2691 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2692 start.set (start.sample, 0);
2696 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2700 check_best_snap ( samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best )
2702 samplepos_t diff = abs( test - presnap );
2703 if ( diff < dist ) {
2708 test = max_samplepos; //reset this so it doesn't get accidentally reused
2712 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2714 if (marks.empty() ) return presnap;
2720 before = after = max_samplepos;
2722 //get marks to either side of presnap
2723 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2724 while ( m != marks.end() && (m->position < presnap) ) {
2728 if (m == marks.end ()) {
2729 /* ran out of marks */
2730 before = marks.back().position;
2733 after = m->position;
2735 if (m != marks.begin ()) {
2737 before = m->position;
2740 if (before == max_samplepos && after == max_samplepos) {
2741 /* No smpte to snap to, so just don't snap */
2743 } else if (before == max_samplepos) {
2745 } else if (after == max_samplepos) {
2748 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2750 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2752 else if (direction == 0 ) {
2753 if ((presnap - before) < (after - presnap)) {
2765 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2771 _session->locations()->marks_either_side (presnap, before, after);
2773 if (before == max_samplepos && after == max_samplepos) {
2774 /* No marks to snap to, so just don't snap */
2776 } else if (before == max_samplepos) {
2778 } else if (after == max_samplepos) {
2781 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2783 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2785 } else if (direction == 0 ) {
2786 if ((presnap - before) < (after - presnap)) {
2798 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2800 const samplepos_t presnap = start.sample;
2802 samplepos_t test = max_samplepos; //for each snap, we'll use this value
2803 samplepos_t dist = max_samplepos; //this records the distance of the best snap result we've found so far
2804 samplepos_t best = max_samplepos; //this records the best snap-result we've found so far
2806 //check snap-to-marker
2807 if ( UIConfiguration::instance().get_snap_to_marks() ) {
2812 test = marker_snap_to_internal ( presnap, direction );
2813 check_best_snap(presnap, test, dist, best);
2816 //check snap-to-region-{start/end/sync}
2817 if ( UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync() ) {
2818 if (!region_boundary_cache.empty()) {
2820 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2821 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2823 if (direction > 0) {
2824 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2826 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2829 if (next != region_boundary_cache.begin ()) {
2834 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2835 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2837 if (presnap > (p + n) / 2) {
2844 check_best_snap(presnap, test, dist, best);
2848 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone) ) {
2850 //if SnapToGrid is selected, the user wants to prioritize the music grid
2851 //in this case we should reset the best distance, so Grid will prevail
2852 dist = max_samplepos;
2854 test = snap_to_grid (grid_marks, presnap, direction);
2855 check_best_snap(presnap, test, dist, best);
2858 //now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2859 //this also helps to avoid snapping to somewhere the user can't see. ( i.e.: I clicked on a region and it disappeared!! )
2860 //ToDo: perhaps this should only occur if EditPointMouse?
2861 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2863 start.set (best, 0);
2865 } else if (presnap > best) {
2866 if (presnap > (best+ snap_threshold_s)) {
2869 } else if (presnap < best) {
2870 if (presnap < (best - snap_threshold_s)) {
2875 start.set (best, 0);
2880 Editor::setup_toolbar ()
2882 HBox* mode_box = manage(new HBox);
2883 mode_box->set_border_width (2);
2884 mode_box->set_spacing(2);
2886 HBox* mouse_mode_box = manage (new HBox);
2887 HBox* mouse_mode_hbox = manage (new HBox);
2888 VBox* mouse_mode_vbox = manage (new VBox);
2889 Alignment* mouse_mode_align = manage (new Alignment);
2891 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2892 mouse_mode_size_group->add_widget (smart_mode_button);
2893 mouse_mode_size_group->add_widget (mouse_move_button);
2894 mouse_mode_size_group->add_widget (mouse_cut_button);
2895 mouse_mode_size_group->add_widget (mouse_select_button);
2896 mouse_mode_size_group->add_widget (mouse_timefx_button);
2897 mouse_mode_size_group->add_widget (mouse_audition_button);
2898 mouse_mode_size_group->add_widget (mouse_draw_button);
2899 mouse_mode_size_group->add_widget (mouse_content_button);
2901 if (!Profile->get_mixbus()) {
2902 mouse_mode_size_group->add_widget (zoom_in_button);
2903 mouse_mode_size_group->add_widget (zoom_out_button);
2904 mouse_mode_size_group->add_widget (zoom_out_full_button);
2905 mouse_mode_size_group->add_widget (zoom_focus_selector);
2906 mouse_mode_size_group->add_widget (tav_shrink_button);
2907 mouse_mode_size_group->add_widget (tav_expand_button);
2909 mouse_mode_size_group->add_widget (zoom_preset_selector);
2910 mouse_mode_size_group->add_widget (visible_tracks_selector);
2913 mouse_mode_size_group->add_widget (grid_type_selector);
2914 mouse_mode_size_group->add_widget (snap_mode_button);
2916 mouse_mode_size_group->add_widget (edit_point_selector);
2917 mouse_mode_size_group->add_widget (edit_mode_selector);
2919 mouse_mode_size_group->add_widget (*nudge_clock);
2920 mouse_mode_size_group->add_widget (nudge_forward_button);
2921 mouse_mode_size_group->add_widget (nudge_backward_button);
2923 mouse_mode_hbox->set_spacing (2);
2925 if (!ARDOUR::Profile->get_trx()) {
2926 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2929 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2930 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2932 if (!ARDOUR::Profile->get_mixbus()) {
2933 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2934 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2937 if (!ARDOUR::Profile->get_trx()) {
2938 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2939 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2940 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2943 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2945 mouse_mode_align->add (*mouse_mode_vbox);
2946 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2948 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2950 edit_mode_selector.set_name ("mouse mode button");
2952 if (!ARDOUR::Profile->get_trx()) {
2953 mode_box->pack_start (edit_mode_selector, false, false);
2954 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2955 mode_box->pack_start (edit_point_selector, false, false);
2956 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2959 mode_box->pack_start (*mouse_mode_box, false, false);
2963 _zoom_box.set_spacing (2);
2964 _zoom_box.set_border_width (2);
2968 zoom_preset_selector.set_name ("zoom button");
2969 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2971 zoom_in_button.set_name ("zoom button");
2972 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2973 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2974 zoom_in_button.set_related_action (act);
2976 zoom_out_button.set_name ("zoom button");
2977 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2978 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2979 zoom_out_button.set_related_action (act);
2981 zoom_out_full_button.set_name ("zoom button");
2982 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2983 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2984 zoom_out_full_button.set_related_action (act);
2986 zoom_focus_selector.set_name ("zoom button");
2988 if (ARDOUR::Profile->get_mixbus()) {
2989 _zoom_box.pack_start (zoom_preset_selector, false, false);
2990 } else if (ARDOUR::Profile->get_trx()) {
2991 mode_box->pack_start (zoom_out_button, false, false);
2992 mode_box->pack_start (zoom_in_button, false, false);
2994 _zoom_box.pack_start (zoom_out_button, false, false);
2995 _zoom_box.pack_start (zoom_in_button, false, false);
2996 _zoom_box.pack_start (zoom_out_full_button, false, false);
2997 _zoom_box.pack_start (zoom_focus_selector, false, false);
3000 /* Track zoom buttons */
3001 _track_box.set_spacing (2);
3002 _track_box.set_border_width (2);
3004 visible_tracks_selector.set_name ("zoom button");
3005 if (Profile->get_mixbus()) {
3006 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3008 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3011 tav_expand_button.set_name ("zoom button");
3012 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3013 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3014 tav_expand_button.set_related_action (act);
3016 tav_shrink_button.set_name ("zoom button");
3017 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3018 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3019 tav_shrink_button.set_related_action (act);
3021 if (ARDOUR::Profile->get_mixbus()) {
3022 _track_box.pack_start (visible_tracks_selector);
3023 } else if (ARDOUR::Profile->get_trx()) {
3024 _track_box.pack_start (tav_shrink_button);
3025 _track_box.pack_start (tav_expand_button);
3027 _track_box.pack_start (visible_tracks_selector);
3028 _track_box.pack_start (tav_shrink_button);
3029 _track_box.pack_start (tav_expand_button);
3032 snap_box.set_spacing (2);
3033 snap_box.set_border_width (2);
3035 grid_type_selector.set_name ("mouse mode button");
3037 snap_mode_button.set_name ("mouse mode button");
3039 edit_point_selector.set_name ("mouse mode button");
3041 snap_box.pack_start (snap_mode_button, false, false);
3042 snap_box.pack_start (grid_type_selector, false, false);
3046 HBox *nudge_box = manage (new HBox);
3047 nudge_box->set_spacing (2);
3048 nudge_box->set_border_width (2);
3050 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3051 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3053 nudge_box->pack_start (nudge_backward_button, false, false);
3054 nudge_box->pack_start (nudge_forward_button, false, false);
3055 nudge_box->pack_start (*nudge_clock, false, false);
3058 /* Pack everything in... */
3060 toolbar_hbox.set_spacing (2);
3061 toolbar_hbox.set_border_width (2);
3063 toolbar_hbox.pack_start (*mode_box, false, false);
3065 if (!ARDOUR::Profile->get_trx()) {
3067 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3069 toolbar_hbox.pack_start (snap_box, false, false);
3071 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3073 toolbar_hbox.pack_start (*nudge_box, false, false);
3075 //zoom tools on right ege
3077 toolbar_hbox.pack_end (_zoom_box, false, false);
3079 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3081 toolbar_hbox.pack_end (_track_box, false, false);
3085 toolbar_hbox.show_all ();
3089 Editor::build_edit_point_menu ()
3091 using namespace Menu_Helpers;
3093 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3094 if(!Profile->get_mixbus())
3095 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3096 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3098 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3102 Editor::build_edit_mode_menu ()
3104 using namespace Menu_Helpers;
3106 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3107 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3108 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3109 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3111 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3115 Editor::build_grid_type_menu ()
3117 using namespace Menu_Helpers;
3119 //main grid: bars, quarter-notes, etc
3120 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3121 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3122 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3123 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3124 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3125 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3126 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3127 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3130 grid_type_selector.AddMenuElem(SeparatorElem());
3131 Gtk::Menu *_triplet_menu = manage (new Menu);
3132 MenuList& triplet_items (_triplet_menu->items());
3134 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3) ));
3135 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6) ));
3136 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12) ));
3137 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24) ));
3139 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3142 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3143 MenuList& quintuplet_items (_quintuplet_menu->items());
3145 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5) ));
3146 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10) ));
3147 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20) ));
3149 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3152 Gtk::Menu *_septuplet_menu = manage (new Menu);
3153 MenuList& septuplet_items (_septuplet_menu->items());
3155 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7) ));
3156 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14) ));
3157 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28) ));
3159 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3161 grid_type_selector.AddMenuElem(SeparatorElem());
3162 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
3163 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3164 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
3166 set_size_request_to_display_given_text (grid_type_selector, _("Long Grid"), COMBO_TRIANGLE_WIDTH, 2); //problem: some of the rarely-used grid names are very long. Just do something arbitary, translators: rename this if needed
3170 Editor::setup_tooltips ()
3172 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3173 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3174 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3175 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3176 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3177 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3178 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3179 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3180 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3181 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3182 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3183 set_tooltip (zoom_in_button, _("Zoom In"));
3184 set_tooltip (zoom_out_button, _("Zoom Out"));
3185 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3186 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3187 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3188 set_tooltip (tav_expand_button, _("Expand Tracks"));
3189 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3190 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3191 set_tooltip (grid_type_selector, _("Grid Mode"));
3192 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3193 set_tooltip (edit_point_selector, _("Edit Point"));
3194 set_tooltip (edit_mode_selector, _("Edit Mode"));
3195 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3199 Editor::convert_drop_to_paths (
3200 vector<string>& paths,
3201 const RefPtr<Gdk::DragContext>& /*context*/,
3204 const SelectionData& data,
3208 if (_session == 0) {
3212 vector<string> uris = data.get_uris();
3216 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3217 are actually URI lists. So do it by hand.
3220 if (data.get_target() != "text/plain") {
3224 /* Parse the "uri-list" format that Nautilus provides,
3225 where each pathname is delimited by \r\n.
3227 THERE MAY BE NO NULL TERMINATING CHAR!!!
3230 string txt = data.get_text();
3234 p = (char *) malloc (txt.length() + 1);
3235 txt.copy (p, txt.length(), 0);
3236 p[txt.length()] = '\0';
3242 while (g_ascii_isspace (*p))
3246 while (*q && (*q != '\n') && (*q != '\r')) {
3253 while (q > p && g_ascii_isspace (*q))
3258 uris.push_back (string (p, q - p + 1));
3262 p = strchr (p, '\n');
3274 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3275 if ((*i).substr (0,7) == "file://") {
3276 paths.push_back (Glib::filename_from_uri (*i));
3284 Editor::new_tempo_section ()
3289 Editor::map_transport_state ()
3291 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3293 if (_session && _session->transport_stopped()) {
3294 have_pending_keyboard_selection = false;
3297 update_loop_range_view ();
3301 Editor::transport_looped ()
3303 /* reset Playhead position interpolation.
3304 * see Editor::super_rapid_screen_update
3306 _last_update_time = 0;
3312 Editor::begin_selection_op_history ()
3314 selection_op_cmd_depth = 0;
3315 selection_op_history_it = 0;
3317 while(!selection_op_history.empty()) {
3318 delete selection_op_history.front();
3319 selection_op_history.pop_front();
3322 selection_undo_action->set_sensitive (false);
3323 selection_redo_action->set_sensitive (false);
3324 selection_op_history.push_front (&_selection_memento->get_state ());
3328 Editor::begin_reversible_selection_op (string name)
3331 //cerr << name << endl;
3332 /* begin/commit pairs can be nested */
3333 selection_op_cmd_depth++;
3338 Editor::commit_reversible_selection_op ()
3341 if (selection_op_cmd_depth == 1) {
3343 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3345 The user has undone some selection ops and then made a new one,
3346 making anything earlier in the list invalid.
3349 list<XMLNode *>::iterator it = selection_op_history.begin();
3350 list<XMLNode *>::iterator e_it = it;
3351 advance (e_it, selection_op_history_it);
3353 for ( ; it != e_it; ++it) {
3356 selection_op_history.erase (selection_op_history.begin(), e_it);
3359 selection_op_history.push_front (&_selection_memento->get_state ());
3360 selection_op_history_it = 0;
3362 selection_undo_action->set_sensitive (true);
3363 selection_redo_action->set_sensitive (false);
3366 if (selection_op_cmd_depth > 0) {
3367 selection_op_cmd_depth--;
3373 Editor::undo_selection_op ()
3376 selection_op_history_it++;
3378 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3379 if (n == selection_op_history_it) {
3380 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3381 selection_redo_action->set_sensitive (true);
3385 /* is there an earlier entry? */
3386 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3387 selection_undo_action->set_sensitive (false);
3393 Editor::redo_selection_op ()
3396 if (selection_op_history_it > 0) {
3397 selection_op_history_it--;
3400 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3401 if (n == selection_op_history_it) {
3402 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3403 selection_undo_action->set_sensitive (true);
3408 if (selection_op_history_it == 0) {
3409 selection_redo_action->set_sensitive (false);
3415 Editor::begin_reversible_command (string name)
3418 before.push_back (&_selection_memento->get_state ());
3419 _session->begin_reversible_command (name);
3424 Editor::begin_reversible_command (GQuark q)
3427 before.push_back (&_selection_memento->get_state ());
3428 _session->begin_reversible_command (q);
3433 Editor::abort_reversible_command ()
3436 while(!before.empty()) {
3437 delete before.front();
3440 _session->abort_reversible_command ();
3445 Editor::commit_reversible_command ()
3448 if (before.size() == 1) {
3449 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3450 redo_action->set_sensitive(false);
3451 undo_action->set_sensitive(true);
3452 begin_selection_op_history ();
3455 if (before.empty()) {
3456 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3461 _session->commit_reversible_command ();
3466 Editor::history_changed ()
3470 if (undo_action && _session) {
3471 if (_session->undo_depth() == 0) {
3472 label = S_("Command|Undo");
3474 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3476 undo_action->property_label() = label;
3479 if (redo_action && _session) {
3480 if (_session->redo_depth() == 0) {
3482 redo_action->set_sensitive (false);
3484 label = string_compose(_("Redo (%1)"), _session->next_redo());
3485 redo_action->set_sensitive (true);
3487 redo_action->property_label() = label;
3492 Editor::duplicate_range (bool with_dialog)
3496 RegionSelection rs = get_regions_from_selection_and_entered ();
3498 if ( selection->time.length() == 0 && rs.empty()) {
3504 ArdourDialog win (_("Duplicate"));
3505 Label label (_("Number of duplications:"));
3506 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3507 SpinButton spinner (adjustment, 0.0, 1);
3510 win.get_vbox()->set_spacing (12);
3511 win.get_vbox()->pack_start (hbox);
3512 hbox.set_border_width (6);
3513 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3515 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3516 place, visually. so do this by hand.
3519 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3520 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3521 spinner.grab_focus();
3527 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3528 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3529 win.set_default_response (RESPONSE_ACCEPT);
3531 spinner.grab_focus ();
3533 switch (win.run ()) {
3534 case RESPONSE_ACCEPT:
3540 times = adjustment.get_value();
3543 if ((current_mouse_mode() == MouseRange)) {
3544 if (selection->time.length()) {
3545 duplicate_selection (times);
3547 } else if (get_smart_mode()) {
3548 if (selection->time.length()) {
3549 duplicate_selection (times);
3551 duplicate_some_regions (rs, times);
3553 duplicate_some_regions (rs, times);
3558 Editor::set_edit_mode (EditMode m)
3560 Config->set_edit_mode (m);
3564 Editor::cycle_edit_mode ()
3566 switch (Config->get_edit_mode()) {
3568 Config->set_edit_mode (Ripple);
3572 Config->set_edit_mode (Lock);
3575 Config->set_edit_mode (Slide);
3581 Editor::edit_mode_selection_done ( EditMode m )
3583 Config->set_edit_mode ( m );
3587 Editor::grid_type_selection_done (GridType gridtype)
3589 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3591 ract->set_active ();
3596 Editor::snap_mode_selection_done (SnapMode mode)
3598 RefPtr<RadioAction> ract = snap_mode_action (mode);
3601 ract->set_active (true);
3606 Editor::cycle_edit_point (bool with_marker)
3608 if(Profile->get_mixbus())
3609 with_marker = false;
3611 switch (_edit_point) {
3613 set_edit_point_preference (EditAtPlayhead);
3615 case EditAtPlayhead:
3617 set_edit_point_preference (EditAtSelectedMarker);
3619 set_edit_point_preference (EditAtMouse);
3622 case EditAtSelectedMarker:
3623 set_edit_point_preference (EditAtMouse);
3629 Editor::edit_point_selection_done (EditPoint ep)
3631 set_edit_point_preference ( ep );
3635 Editor::build_zoom_focus_menu ()
3637 using namespace Menu_Helpers;
3639 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3640 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3641 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3642 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3643 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3644 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3646 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3650 Editor::zoom_focus_selection_done ( ZoomFocus f )
3652 RefPtr<RadioAction> ract = zoom_focus_action (f);
3654 ract->set_active ();
3659 Editor::build_track_count_menu ()
3661 using namespace Menu_Helpers;
3663 if (!Profile->get_mixbus()) {
3664 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3665 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3668 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3669 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3670 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3671 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3672 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3673 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3674 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3675 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3676 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3678 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3679 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3680 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3681 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3682 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3683 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3684 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3685 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3686 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3687 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3689 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3690 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3691 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3692 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3693 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3694 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3695 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3696 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3697 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3698 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3699 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3700 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3705 Editor::set_zoom_preset (int64_t ms)
3708 temporal_zoom_session();
3712 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3713 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3717 Editor::set_visible_track_count (int32_t n)
3719 _visible_track_count = n;
3721 /* if the canvas hasn't really been allocated any size yet, just
3722 record the desired number of visible tracks and return. when canvas
3723 allocation happens, we will get called again and then we can do the
3727 if (_visible_canvas_height <= 1) {
3733 DisplaySuspender ds;
3735 if (_visible_track_count > 0) {
3736 h = trackviews_height() / _visible_track_count;
3737 std::ostringstream s;
3738 s << _visible_track_count;
3740 } else if (_visible_track_count == 0) {
3742 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3743 if ((*i)->marked_for_display()) {
3745 TimeAxisView::Children cl ((*i)->get_child_list ());
3746 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3747 if ((*j)->marked_for_display()) {
3754 visible_tracks_selector.set_text (X_("*"));
3757 h = trackviews_height() / n;
3760 /* negative value means that the visible track count has
3761 been overridden by explicit track height changes.
3763 visible_tracks_selector.set_text (X_("*"));
3767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3768 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3771 if (str != visible_tracks_selector.get_text()) {
3772 visible_tracks_selector.set_text (str);
3777 Editor::override_visible_track_count ()
3779 _visible_track_count = -1;
3780 visible_tracks_selector.set_text ( _("*") );
3784 Editor::edit_controls_button_release (GdkEventButton* ev)
3786 if (Keyboard::is_context_menu_event (ev)) {
3787 ARDOUR_UI::instance()->add_route ();
3788 } else if (ev->button == 1) {
3789 selection->clear_tracks ();
3796 Editor::mouse_select_button_release (GdkEventButton* ev)
3798 /* this handles just right-clicks */
3800 if (ev->button != 3) {
3808 Editor::set_zoom_focus (ZoomFocus f)
3810 string str = zoom_focus_strings[(int)f];
3812 if (str != zoom_focus_selector.get_text()) {
3813 zoom_focus_selector.set_text (str);
3816 if (zoom_focus != f) {
3823 Editor::cycle_zoom_focus ()
3825 switch (zoom_focus) {
3827 set_zoom_focus (ZoomFocusRight);
3829 case ZoomFocusRight:
3830 set_zoom_focus (ZoomFocusCenter);
3832 case ZoomFocusCenter:
3833 set_zoom_focus (ZoomFocusPlayhead);
3835 case ZoomFocusPlayhead:
3836 set_zoom_focus (ZoomFocusMouse);
3838 case ZoomFocusMouse:
3839 set_zoom_focus (ZoomFocusEdit);
3842 set_zoom_focus (ZoomFocusLeft);
3848 Editor::update_grid ()
3850 if ( grid_musical() ) {
3851 std::vector<TempoMap::BBTPoint> grid;
3852 if (bbt_ruler_scale != bbt_show_many) {
3853 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3855 maybe_draw_grid_lines ();
3856 } else if ( grid_nonmusical() ) {
3857 maybe_draw_grid_lines ();
3864 Editor::toggle_follow_playhead ()
3866 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3868 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3869 set_follow_playhead (tact->get_active());
3873 /** @param yn true to follow playhead, otherwise false.
3874 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3877 Editor::set_follow_playhead (bool yn, bool catch_up)
3879 if (_follow_playhead != yn) {
3880 if ((_follow_playhead = yn) == true && catch_up) {
3882 reset_x_origin_to_follow_playhead ();
3889 Editor::toggle_stationary_playhead ()
3891 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3893 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3894 set_stationary_playhead (tact->get_active());
3899 Editor::set_stationary_playhead (bool yn)
3901 if (_stationary_playhead != yn) {
3902 if ((_stationary_playhead = yn) == true) {
3904 // FIXME need a 3.0 equivalent of this 2.X call
3905 // update_current_screen ();
3912 Editor::playlist_selector () const
3914 return *_playlist_selector;
3918 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3920 if (paste_count == 0) {
3921 /* don't bother calculating an offset that will be zero anyway */
3925 /* calculate basic unsnapped multi-paste offset */
3926 samplecnt_t offset = paste_count * duration;
3928 /* snap offset so pos + offset is aligned to the grid */
3929 MusicSample offset_pos (pos + offset, 0);
3930 snap_to(offset_pos, RoundUpMaybe);
3931 offset = offset_pos.sample - pos;
3937 Editor::get_grid_beat_divisions(samplepos_t position)
3939 switch (_grid_type) {
3940 case GridTypeBeatDiv32: return 32;
3941 case GridTypeBeatDiv28: return 28;
3942 case GridTypeBeatDiv24: return 24;
3943 case GridTypeBeatDiv20: return 20;
3944 case GridTypeBeatDiv16: return 16;
3945 case GridTypeBeatDiv14: return 14;
3946 case GridTypeBeatDiv12: return 12;
3947 case GridTypeBeatDiv10: return 10;
3948 case GridTypeBeatDiv8: return 8;
3949 case GridTypeBeatDiv7: return 7;
3950 case GridTypeBeatDiv6: return 6;
3951 case GridTypeBeatDiv5: return 5;
3952 case GridTypeBeatDiv4: return 4;
3953 case GridTypeBeatDiv3: return 3;
3954 case GridTypeBeatDiv2: return 2;
3956 case GridTypeNone: return 0;
3957 case GridTypeSmpte: return 0;
3958 case GridTypeMinSec: return 0;
3959 case GridTypeSamples: return 0;
3965 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
3966 if the grid is non-musical, returns 0.
3967 if the grid is snapped to bars, returns -1.
3968 @param event_state the current keyboard modifier mask.
3971 Editor::get_grid_music_divisions (uint32_t event_state)
3973 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
3977 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
3981 switch (_grid_type) {
3982 case GridTypeBeatDiv32: return 32;
3983 case GridTypeBeatDiv28: return 28;
3984 case GridTypeBeatDiv24: return 24;
3985 case GridTypeBeatDiv20: return 20;
3986 case GridTypeBeatDiv16: return 16;
3987 case GridTypeBeatDiv14: return 14;
3988 case GridTypeBeatDiv12: return 12;
3989 case GridTypeBeatDiv10: return 10;
3990 case GridTypeBeatDiv8: return 8;
3991 case GridTypeBeatDiv7: return 7;
3992 case GridTypeBeatDiv6: return 6;
3993 case GridTypeBeatDiv5: return 5;
3994 case GridTypeBeatDiv4: return 4;
3995 case GridTypeBeatDiv3: return 3;
3996 case GridTypeBeatDiv2: return 2;
3997 case GridTypeBeat: return 1;
3998 case GridTypeBar : return -1;
4000 case GridTypeNone: return 0;
4001 case GridTypeSmpte: return 0;
4002 case GridTypeMinSec: return 0;
4003 case GridTypeSamples: return 0;
4009 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4013 const unsigned divisions = get_grid_beat_divisions(position);
4015 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4018 switch (_grid_type) {
4020 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4023 const Meter& m = _session->tempo_map().meter_at_sample (position);
4024 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4032 return Temporal::Beats();
4036 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4040 ret = nudge_clock->current_duration (pos);
4041 next = ret + 1; /* XXXX fix me */
4047 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4049 ArdourDialog dialog (_("Playlist Deletion"));
4050 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4051 "If it is kept, its audio files will not be cleaned.\n"
4052 "If it is deleted, audio files used by it alone will be cleaned."),
4055 dialog.set_position (WIN_POS_CENTER);
4056 dialog.get_vbox()->pack_start (label);
4060 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4061 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4062 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4063 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4064 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4066 // by default gtk uses the left most button
4067 keep->grab_focus ();
4069 switch (dialog.run ()) {
4071 /* keep this and all remaining ones */
4076 /* delete this and all others */
4080 case RESPONSE_ACCEPT:
4081 /* delete the playlist */
4085 case RESPONSE_REJECT:
4086 /* keep the playlist */
4098 Editor::audio_region_selection_covers (samplepos_t where)
4100 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4101 if ((*a)->region()->covers (where)) {
4110 Editor::prepare_for_cleanup ()
4112 cut_buffer->clear_regions ();
4113 cut_buffer->clear_playlists ();
4115 selection->clear_regions ();
4116 selection->clear_playlists ();
4118 _regions->suspend_redisplay ();
4122 Editor::finish_cleanup ()
4124 _regions->resume_redisplay ();
4128 Editor::transport_loop_location()
4131 return _session->locations()->auto_loop_location();
4138 Editor::transport_punch_location()
4141 return _session->locations()->auto_punch_location();
4148 Editor::control_layout_scroll (GdkEventScroll* ev)
4150 /* Just forward to the normal canvas scroll method. The coordinate
4151 systems are different but since the canvas is always larger than the
4152 track headers, and aligned with the trackview area, this will work.
4154 In the not too distant future this layout is going away anyway and
4155 headers will be on the canvas.
4157 return canvas_scroll_event (ev, false);
4161 Editor::session_state_saved (string)
4164 _snapshots->redisplay ();
4168 Editor::maximise_editing_space ()
4174 Gtk::Window* toplevel = current_toplevel();
4177 toplevel->fullscreen ();
4183 Editor::restore_editing_space ()
4189 Gtk::Window* toplevel = current_toplevel();
4192 toplevel->unfullscreen();
4198 * Make new playlists for a given track and also any others that belong
4199 * to the same active route group with the `select' property.
4204 Editor::new_playlists (TimeAxisView* v)
4206 begin_reversible_command (_("new playlists"));
4207 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4208 _session->playlists->get (playlists);
4209 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4210 commit_reversible_command ();
4214 * Use a copy of the current playlist for a given track and also any others that belong
4215 * to the same active route group with the `select' property.
4220 Editor::copy_playlists (TimeAxisView* v)
4222 begin_reversible_command (_("copy playlists"));
4223 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4224 _session->playlists->get (playlists);
4225 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4226 commit_reversible_command ();
4229 /** Clear the current playlist for a given track and also any others that belong
4230 * to the same active route group with the `select' property.
4235 Editor::clear_playlists (TimeAxisView* v)
4237 begin_reversible_command (_("clear playlists"));
4238 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4239 _session->playlists->get (playlists);
4240 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4241 commit_reversible_command ();
4245 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4247 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4251 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4253 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4257 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4259 atv.clear_playlist ();
4263 Editor::get_y_origin () const
4265 return vertical_adjustment.get_value ();
4268 /** Queue up a change to the viewport x origin.
4269 * @param sample New x origin.
4272 Editor::reset_x_origin (samplepos_t sample)
4274 pending_visual_change.add (VisualChange::TimeOrigin);
4275 pending_visual_change.time_origin = sample;
4276 ensure_visual_change_idle_handler ();
4280 Editor::reset_y_origin (double y)
4282 pending_visual_change.add (VisualChange::YOrigin);
4283 pending_visual_change.y_origin = y;
4284 ensure_visual_change_idle_handler ();
4288 Editor::reset_zoom (samplecnt_t spp)
4290 if (spp == samples_per_pixel) {
4294 pending_visual_change.add (VisualChange::ZoomLevel);
4295 pending_visual_change.samples_per_pixel = spp;
4296 ensure_visual_change_idle_handler ();
4300 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4302 reset_x_origin (sample);
4305 if (!no_save_visual) {
4306 undo_visual_stack.push_back (current_visual_state(false));
4310 Editor::VisualState::VisualState (bool with_tracks)
4311 : gui_state (with_tracks ? new GUIObjectState : 0)
4315 Editor::VisualState::~VisualState ()
4320 Editor::VisualState*
4321 Editor::current_visual_state (bool with_tracks)
4323 VisualState* vs = new VisualState (with_tracks);
4324 vs->y_position = vertical_adjustment.get_value();
4325 vs->samples_per_pixel = samples_per_pixel;
4326 vs->_leftmost_sample = _leftmost_sample;
4327 vs->zoom_focus = zoom_focus;
4330 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4337 Editor::undo_visual_state ()
4339 if (undo_visual_stack.empty()) {
4343 VisualState* vs = undo_visual_stack.back();
4344 undo_visual_stack.pop_back();
4347 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4350 use_visual_state (*vs);
4355 Editor::redo_visual_state ()
4357 if (redo_visual_stack.empty()) {
4361 VisualState* vs = redo_visual_stack.back();
4362 redo_visual_stack.pop_back();
4364 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4365 // why do we check here?
4366 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4369 use_visual_state (*vs);
4374 Editor::swap_visual_state ()
4376 if (undo_visual_stack.empty()) {
4377 redo_visual_state ();
4379 undo_visual_state ();
4384 Editor::use_visual_state (VisualState& vs)
4386 PBD::Unwinder<bool> nsv (no_save_visual, true);
4387 DisplaySuspender ds;
4389 vertical_adjustment.set_value (vs.y_position);
4391 set_zoom_focus (vs.zoom_focus);
4392 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4395 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4397 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4398 (*i)->clear_property_cache();
4399 (*i)->reset_visual_state ();
4403 _routes->update_visibility ();
4406 /** This is the core function that controls the zoom level of the canvas. It is called
4407 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4408 * @param spp new number of samples per pixel
4411 Editor::set_samples_per_pixel (samplecnt_t spp)
4417 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4418 const samplecnt_t lots_of_pixels = 4000;
4420 /* if the zoom level is greater than what you'd get trying to display 3
4421 * days of audio on a really big screen, then it's too big.
4424 if (spp * lots_of_pixels > three_days) {
4428 samples_per_pixel = spp;
4432 Editor::on_samples_per_pixel_changed ()
4434 bool const showing_time_selection = selection->time.length() > 0;
4436 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4437 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4438 (*i)->reshow_selection (selection->time);
4442 ZoomChanged (); /* EMIT_SIGNAL */
4444 ArdourCanvas::GtkCanvasViewport* c;
4446 c = get_track_canvas();
4448 c->canvas()->zoomed ();
4451 if (playhead_cursor) {
4452 playhead_cursor->set_position (playhead_cursor->current_sample ());
4455 refresh_location_display();
4456 _summary->set_overlays_dirty ();
4458 update_marker_labels ();
4464 Editor::playhead_cursor_sample () const
4466 return playhead_cursor->current_sample();
4470 Editor::queue_visual_videotimeline_update ()
4472 pending_visual_change.add (VisualChange::VideoTimeline);
4473 ensure_visual_change_idle_handler ();
4477 Editor::ensure_visual_change_idle_handler ()
4479 if (pending_visual_change.idle_handler_id < 0) {
4480 // see comment in add_to_idle_resize above.
4481 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4482 pending_visual_change.being_handled = false;
4487 Editor::_idle_visual_changer (void* arg)
4489 return static_cast<Editor*>(arg)->idle_visual_changer ();
4493 Editor::pre_render ()
4495 visual_change_queued = false;
4497 if (pending_visual_change.pending != 0) {
4498 ensure_visual_change_idle_handler();
4503 Editor::idle_visual_changer ()
4505 pending_visual_change.idle_handler_id = -1;
4507 if (pending_visual_change.pending == 0) {
4511 /* set_horizontal_position() below (and maybe other calls) call
4512 gtk_main_iteration(), so it's possible that a signal will be handled
4513 half-way through this method. If this signal wants an
4514 idle_visual_changer we must schedule another one after this one, so
4515 mark the idle_handler_id as -1 here to allow that. Also make a note
4516 that we are doing the visual change, so that changes in response to
4517 super-rapid-screen-update can be dropped if we are still processing
4521 if (visual_change_queued) {
4525 pending_visual_change.being_handled = true;
4527 VisualChange vc = pending_visual_change;
4529 pending_visual_change.pending = (VisualChange::Type) 0;
4531 visual_changer (vc);
4533 pending_visual_change.being_handled = false;
4535 visual_change_queued = true;
4537 return 0; /* this is always a one-shot call */
4541 Editor::visual_changer (const VisualChange& vc)
4544 * Changed first so the correct horizontal canvas position is calculated in
4545 * Editor::set_horizontal_position
4547 if (vc.pending & VisualChange::ZoomLevel) {
4548 set_samples_per_pixel (vc.samples_per_pixel);
4551 if (vc.pending & VisualChange::TimeOrigin) {
4552 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4553 set_horizontal_position (new_time_origin);
4556 if (vc.pending & VisualChange::YOrigin) {
4557 vertical_adjustment.set_value (vc.y_origin);
4561 * Now the canvas is in the final state before render the canvas items that
4562 * support the Item::prepare_for_render interface can calculate the correct
4563 * item to visible canvas intersection.
4565 if (vc.pending & VisualChange::ZoomLevel) {
4566 on_samples_per_pixel_changed ();
4568 compute_fixed_ruler_scale ();
4570 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4571 update_tempo_based_rulers ();
4574 if (!(vc.pending & VisualChange::ZoomLevel)) {
4576 * If the canvas is not being zoomed then the canvas items will not change
4577 * and cause Item::prepare_for_render to be called so do it here manually.
4579 * Not ideal, but I can't think of a better solution atm.
4581 _track_canvas->prepare_for_render();
4584 // If we are only scrolling vertically there is no need to update these
4585 if (vc.pending != VisualChange::YOrigin) {
4586 update_fixed_rulers ();
4587 redisplay_grid (true);
4589 /* video frames & position need to be updated for zoom, horiz-scroll
4590 * and (explicitly) VisualChange::VideoTimeline.
4592 update_video_timeline();
4595 _summary->set_overlays_dirty ();
4598 struct EditorOrderTimeAxisSorter {
4599 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4600 return a->order () < b->order ();
4605 Editor::sort_track_selection (TrackViewList& sel)
4607 EditorOrderTimeAxisSorter cmp;
4612 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4615 samplepos_t where = 0;
4616 EditPoint ep = _edit_point;
4618 if (Profile->get_mixbus()) {
4619 if (ep == EditAtSelectedMarker) {
4620 ep = EditAtPlayhead;
4624 if (from_outside_canvas && (ep == EditAtMouse)) {
4625 ep = EditAtPlayhead;
4626 } else if (from_context_menu && (ep == EditAtMouse)) {
4627 return canvas_event_sample (&context_click_event, 0, 0);
4630 if (entered_marker) {
4631 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4632 return entered_marker->position();
4635 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4636 ep = EditAtSelectedMarker;
4639 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4640 ep = EditAtPlayhead;
4643 MusicSample snap_mf (0, 0);
4646 case EditAtPlayhead:
4647 if (_dragging_playhead && _control_scroll_target) {
4648 where = *_control_scroll_target;
4650 where = _session->audible_sample();
4652 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4655 case EditAtSelectedMarker:
4656 if (!selection->markers.empty()) {
4658 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4661 where = loc->start();
4665 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4673 if (!mouse_sample (where, ignored)) {
4674 /* XXX not right but what can we do ? */
4677 snap_mf.sample = where;
4679 where = snap_mf.sample;
4680 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4688 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4690 if (!_session) return;
4692 begin_reversible_command (cmd);
4696 if ((tll = transport_loop_location()) == 0) {
4697 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4698 XMLNode &before = _session->locations()->get_state();
4699 _session->locations()->add (loc, true);
4700 _session->set_auto_loop_location (loc);
4701 XMLNode &after = _session->locations()->get_state();
4702 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4704 XMLNode &before = tll->get_state();
4705 tll->set_hidden (false, this);
4706 tll->set (start, end);
4707 XMLNode &after = tll->get_state();
4708 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4711 commit_reversible_command ();
4715 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4717 if (!_session) return;
4719 begin_reversible_command (cmd);
4723 if ((tpl = transport_punch_location()) == 0) {
4724 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4725 XMLNode &before = _session->locations()->get_state();
4726 _session->locations()->add (loc, true);
4727 _session->set_auto_punch_location (loc);
4728 XMLNode &after = _session->locations()->get_state();
4729 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4731 XMLNode &before = tpl->get_state();
4732 tpl->set_hidden (false, this);
4733 tpl->set (start, end);
4734 XMLNode &after = tpl->get_state();
4735 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4738 commit_reversible_command ();
4741 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4742 * @param rs List to which found regions are added.
4743 * @param where Time to look at.
4744 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4747 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4749 const TrackViewList* tracks;
4752 tracks = &track_views;
4757 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4759 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4762 boost::shared_ptr<Track> tr;
4763 boost::shared_ptr<Playlist> pl;
4765 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4767 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4769 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4770 RegionView* rv = rtv->view()->find_view (*i);
4781 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4783 const TrackViewList* tracks;
4786 tracks = &track_views;
4791 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4792 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4794 boost::shared_ptr<Track> tr;
4795 boost::shared_ptr<Playlist> pl;
4797 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4799 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4801 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4803 RegionView* rv = rtv->view()->find_view (*i);
4814 /** Get regions using the following method:
4816 * Make a region list using:
4817 * (a) any selected regions
4818 * (b) the intersection of any selected tracks and the edit point(*)
4819 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4821 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4823 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4827 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4829 RegionSelection regions;
4831 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4832 regions.add (entered_regionview);
4834 regions = selection->regions;
4837 if ( regions.empty() ) {
4838 TrackViewList tracks = selection->tracks;
4840 if (!tracks.empty()) {
4841 /* no region selected or entered, but some selected tracks:
4842 * act on all regions on the selected tracks at the edit point
4844 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4845 get_regions_at(regions, where, tracks);
4852 /** Get regions using the following method:
4854 * Make a region list using:
4855 * (a) any selected regions
4856 * (b) the intersection of any selected tracks and the edit point(*)
4857 * (c) if neither exists, then whatever region is under the mouse
4859 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4861 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4864 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4866 RegionSelection regions;
4868 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4869 regions.add (entered_regionview);
4871 regions = selection->regions;
4874 if ( regions.empty() ) {
4875 TrackViewList tracks = selection->tracks;
4877 if (!tracks.empty()) {
4878 /* no region selected or entered, but some selected tracks:
4879 * act on all regions on the selected tracks at the edit point
4881 get_regions_at(regions, pos, tracks);
4888 /** Start with regions that are selected, or the entered regionview if none are selected.
4889 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4890 * of the regions that we started with.
4894 Editor::get_regions_from_selection_and_entered () const
4896 RegionSelection regions = selection->regions;
4898 if (regions.empty() && entered_regionview) {
4899 regions.add (entered_regionview);
4906 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4908 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4909 RouteTimeAxisView* rtav;
4911 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4912 boost::shared_ptr<Playlist> pl;
4913 std::vector<boost::shared_ptr<Region> > results;
4914 boost::shared_ptr<Track> tr;
4916 if ((tr = rtav->track()) == 0) {
4921 if ((pl = (tr->playlist())) != 0) {
4922 boost::shared_ptr<Region> r = pl->region_by_id (id);
4924 RegionView* rv = rtav->view()->find_view (r);
4926 regions.push_back (rv);
4935 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4938 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4939 MidiTimeAxisView* mtav;
4941 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4943 mtav->get_per_region_note_selection (selection);
4950 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4952 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4954 RouteTimeAxisView* tatv;
4956 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4958 boost::shared_ptr<Playlist> pl;
4959 vector<boost::shared_ptr<Region> > results;
4961 boost::shared_ptr<Track> tr;
4963 if ((tr = tatv->track()) == 0) {
4968 if ((pl = (tr->playlist())) != 0) {
4969 if (src_comparison) {
4970 pl->get_source_equivalent_regions (region, results);
4972 pl->get_region_list_equivalent_regions (region, results);
4976 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4977 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4978 regions.push_back (marv);
4987 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
4989 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 RouteTimeAxisView* tatv;
4991 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4992 if (!tatv->track()) {
4995 RegionView* marv = tatv->view()->find_view (region);
5005 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5007 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5008 RouteTimeAxisView* rtav;
5009 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5010 if (rtav->route() == route) {
5019 Editor::show_rhythm_ferret ()
5021 if (rhythm_ferret == 0) {
5022 rhythm_ferret = new RhythmFerret(*this);
5025 rhythm_ferret->set_session (_session);
5026 rhythm_ferret->show ();
5027 rhythm_ferret->present ();
5031 Editor::first_idle ()
5033 MessageDialog* dialog = 0;
5035 if (track_views.size() > 1) {
5036 Timers::TimerSuspender t;
5037 dialog = new MessageDialog (
5038 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5042 ARDOUR_UI::instance()->flush_pending (60);
5045 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5049 /* now that all regionviews should exist, setup region selection */
5053 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5054 /* this is cumulative: rs is NOT cleared each time */
5055 get_regionviews_by_id (*pr, rs);
5058 selection->set (rs);
5060 // first idle adds route children (automation tracks), so we need to redisplay here
5061 _routes->redisplay ();
5065 if (_session->undo_depth() == 0) {
5066 undo_action->set_sensitive(false);
5068 redo_action->set_sensitive(false);
5069 begin_selection_op_history ();
5075 Editor::_idle_resize (gpointer arg)
5077 return ((Editor*)arg)->idle_resize ();
5081 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5083 if (resize_idle_id < 0) {
5084 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5085 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5086 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5088 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5089 _pending_resize_amount = 0;
5092 /* make a note of the smallest resulting height, so that we can clamp the
5093 lower limit at TimeAxisView::hSmall */
5095 int32_t min_resulting = INT32_MAX;
5097 _pending_resize_amount += h;
5098 _pending_resize_view = view;
5100 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5102 if (selection->tracks.contains (_pending_resize_view)) {
5103 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5104 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5108 if (min_resulting < 0) {
5113 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5114 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5118 /** Handle pending resizing of tracks */
5120 Editor::idle_resize ()
5122 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5124 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5125 selection->tracks.contains (_pending_resize_view)) {
5127 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5128 if (*i != _pending_resize_view) {
5129 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5134 _pending_resize_amount = 0;
5135 _group_tabs->set_dirty ();
5136 resize_idle_id = -1;
5144 ENSURE_GUI_THREAD (*this, &Editor::located);
5147 playhead_cursor->set_position (_session->audible_sample ());
5148 if (_follow_playhead && !_pending_initial_locate) {
5149 reset_x_origin_to_follow_playhead ();
5153 _pending_locate_request = false;
5154 _pending_initial_locate = false;
5155 _last_update_time = 0;
5159 Editor::region_view_added (RegionView * rv)
5161 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5163 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5164 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5165 if (rv->region()->id () == (*rnote).first) {
5166 mrv->select_notes ((*rnote).second);
5167 selection->pending_midi_note_selection.erase(rnote);
5173 _summary->set_background_dirty ();
5175 mark_region_boundary_cache_dirty ();
5179 Editor::region_view_removed ()
5181 _summary->set_background_dirty ();
5183 mark_region_boundary_cache_dirty ();
5187 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5189 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5190 if ((*j)->stripable() == s) {
5199 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5201 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5202 if ((*j)->control() == c) {
5206 TimeAxisView::Children kids = (*j)->get_child_list ();
5208 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5209 if ((*k)->control() == c) {
5219 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5223 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5224 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5234 Editor::suspend_route_redisplay ()
5237 _routes->suspend_redisplay();
5242 Editor::resume_route_redisplay ()
5245 _routes->redisplay(); // queue redisplay
5246 _routes->resume_redisplay();
5251 Editor::add_vcas (VCAList& vlist)
5255 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5256 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5259 add_stripables (sl);
5263 Editor::add_routes (RouteList& rlist)
5267 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5271 add_stripables (sl);
5275 Editor::add_stripables (StripableList& sl)
5277 list<TimeAxisView*> new_views;
5278 boost::shared_ptr<VCA> v;
5279 boost::shared_ptr<Route> r;
5280 TrackViewList new_selection;
5281 bool from_scratch = (track_views.size() == 0);
5283 sl.sort (Stripable::Sorter());
5285 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5287 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5289 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5291 new_views.push_back (vtv);
5293 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5295 if (r->is_auditioner() || r->is_monitor()) {
5299 RouteTimeAxisView* rtv;
5300 DataType dt = r->input()->default_type();
5302 if (dt == ARDOUR::DataType::AUDIO) {
5303 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5305 } else if (dt == ARDOUR::DataType::MIDI) {
5306 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5309 throw unknown_type();
5312 new_views.push_back (rtv);
5313 track_views.push_back (rtv);
5314 new_selection.push_back (rtv);
5316 rtv->effective_gain_display ();
5318 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5319 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5323 if (new_views.size() > 0) {
5324 _routes->time_axis_views_added (new_views);
5325 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5328 /* note: !new_selection.empty() means that we got some routes rather
5332 if (!from_scratch && !new_selection.empty()) {
5333 selection->set (new_selection);
5334 begin_selection_op_history();
5337 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5338 show_editor_mixer (true);
5341 editor_list_button.set_sensitive (true);
5345 Editor::timeaxisview_deleted (TimeAxisView *tv)
5347 if (tv == entered_track) {
5351 if (_session && _session->deletion_in_progress()) {
5352 /* the situation is under control */
5356 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5358 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5360 _routes->route_removed (tv);
5362 TimeAxisView::Children c = tv->get_child_list ();
5363 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5364 if (entered_track == i->get()) {
5369 /* remove it from the list of track views */
5371 TrackViewList::iterator i;
5373 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5374 i = track_views.erase (i);
5377 /* update whatever the current mixer strip is displaying, if revelant */
5379 boost::shared_ptr<Route> route;
5382 route = rtav->route ();
5385 if (current_mixer_strip && current_mixer_strip->route() == route) {
5387 TimeAxisView* next_tv;
5389 if (track_views.empty()) {
5391 } else if (i == track_views.end()) {
5392 next_tv = track_views.front();
5397 // skip VCAs (cannot be selected, n/a in editor-mixer)
5398 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5399 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5400 next_tv = track_views.front();
5402 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5403 /* just in case: no master, only a VCA remains */
5409 set_selected_mixer_strip (*next_tv);
5411 /* make the editor mixer strip go away setting the
5412 * button to inactive (which also unticks the menu option)
5415 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5421 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5427 DisplaySuspender ds;
5428 PresentationInfo::ChangeSuspender cs;
5430 if (apply_to_selection) {
5431 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5433 TrackSelection::iterator j = i;
5436 hide_track_in_display (*i, false);
5441 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5443 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5444 // this will hide the mixer strip
5445 set_selected_mixer_strip (*tv);
5448 _routes->hide_track_in_display (*tv);
5453 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5458 _routes->show_track_in_display (*tv);
5459 if (move_into_view) {
5460 ensure_time_axis_view_is_visible (*tv, false);
5465 Editor::sync_track_view_list_and_routes ()
5467 track_views = TrackViewList (_routes->views ());
5469 _summary->set_background_dirty();
5470 _group_tabs->set_dirty ();
5472 return false; // do not call again (until needed)
5476 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5478 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5483 /** Find a StripableTimeAxisView by the ID of its stripable */
5484 StripableTimeAxisView*
5485 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5487 StripableTimeAxisView* v;
5489 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5490 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5491 if(v->stripable()->id() == id) {
5501 Editor::fit_route_group (RouteGroup *g)
5503 TrackViewList ts = axis_views_from_routes (g->route_list ());
5508 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5510 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5513 _session->cancel_audition ();
5517 if (_session->is_auditioning()) {
5518 _session->cancel_audition ();
5519 if (r == last_audition_region) {
5524 _session->audition_region (r);
5525 last_audition_region = r;
5530 Editor::hide_a_region (boost::shared_ptr<Region> r)
5532 r->set_hidden (true);
5536 Editor::show_a_region (boost::shared_ptr<Region> r)
5538 r->set_hidden (false);
5542 Editor::audition_region_from_region_list ()
5544 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5548 Editor::hide_region_from_region_list ()
5550 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5554 Editor::show_region_in_region_list ()
5556 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5560 Editor::step_edit_status_change (bool yn)
5563 start_step_editing ();
5565 stop_step_editing ();
5570 Editor::start_step_editing ()
5572 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5576 Editor::stop_step_editing ()
5578 step_edit_connection.disconnect ();
5582 Editor::check_step_edit ()
5584 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5585 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5587 mtv->check_step_edit ();
5591 return true; // do it again, till we stop
5595 Editor::scroll_press (Direction dir)
5597 ++_scroll_callbacks;
5599 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5600 /* delay the first auto-repeat */
5606 scroll_backward (1);
5614 scroll_up_one_track ();
5618 scroll_down_one_track ();
5622 /* do hacky auto-repeat */
5623 if (!_scroll_connection.connected ()) {
5625 _scroll_connection = Glib::signal_timeout().connect (
5626 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5629 _scroll_callbacks = 0;
5636 Editor::scroll_release ()
5638 _scroll_connection.disconnect ();
5641 /** Queue a change for the Editor viewport x origin to follow the playhead */
5643 Editor::reset_x_origin_to_follow_playhead ()
5645 samplepos_t const sample = playhead_cursor->current_sample ();
5647 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5649 if (_session->transport_speed() < 0) {
5651 if (sample > (current_page_samples() / 2)) {
5652 center_screen (sample-(current_page_samples()/2));
5654 center_screen (current_page_samples()/2);
5661 if (sample < _leftmost_sample) {
5663 if (_session->transport_rolling()) {
5664 /* rolling; end up with the playhead at the right of the page */
5665 l = sample - current_page_samples ();
5667 /* not rolling: end up with the playhead 1/4 of the way along the page */
5668 l = sample - current_page_samples() / 4;
5672 if (_session->transport_rolling()) {
5673 /* rolling: end up with the playhead on the left of the page */
5676 /* not rolling: end up with the playhead 3/4 of the way along the page */
5677 l = sample - 3 * current_page_samples() / 4;
5685 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5691 Editor::super_rapid_screen_update ()
5693 if (!_session || !_session->engine().running()) {
5697 /* METERING / MIXER STRIPS */
5699 /* update track meters, if required */
5700 if (contents().is_mapped() && meters_running) {
5701 RouteTimeAxisView* rtv;
5702 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5703 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5704 rtv->fast_update ();
5709 /* and any current mixer strip */
5710 if (current_mixer_strip) {
5711 current_mixer_strip->fast_update ();
5714 bool latent_locate = false;
5715 samplepos_t sample = _session->audible_sample (&latent_locate);
5716 const int64_t now = g_get_monotonic_time ();
5719 if (_session->exporting ()) {
5720 /* freewheel/export may be faster or slower than transport_speed() / SR.
5721 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5723 _last_update_time = 0;
5726 if (_last_update_time > 0) {
5727 /* interpolate and smoothen playhead position */
5728 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5729 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5730 err = sample - guess;
5732 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5733 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5736 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5738 err, _err_screen_engine);
5743 _err_screen_engine = 0;
5746 if (err > 8192 || latent_locate) {
5747 // in case of x-runs or freewheeling
5748 _last_update_time = 0;
5749 sample = _session->audible_sample ();
5751 _last_update_time = now;
5754 //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
5756 MusicSample where (sample, 0);
5757 if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
5758 snapped_cursor->hide ();
5759 } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
5760 snap_to (where); // can't use snap_to_with_modifier?
5761 snapped_cursor->set_position (where.sample);
5762 snapped_cursor->show ();
5763 } else if ( _edit_point == EditAtSelectedMarker ) {
5764 //NOTE: I don't think EditAtSelectedMarker should snap. they are what they are.
5765 //however, the current editing code -does- snap so I'll draw it that way for now.
5766 if ( !selection->markers.empty() ) {
5767 MusicSample ms (selection->markers.front()->position(), 0);
5768 snap_to (ms); // should use snap_to_with_modifier?
5769 snapped_cursor->set_position ( ms.sample );
5770 snapped_cursor->show ();
5772 } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it.
5773 snapped_cursor->show ();
5774 } else { //mouse is out of the editing canvas. hide the snapped_cursor
5775 snapped_cursor->hide ();
5778 /* There are a few reasons why we might not update the playhead / viewport stuff:
5780 * 1. we don't update things when there's a pending locate request, otherwise
5781 * when the editor requests a locate there is a chance that this method
5782 * will move the playhead before the locate request is processed, causing
5784 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5785 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5787 if (_pending_locate_request) {
5788 _last_update_time = 0;
5792 if (_dragging_playhead) {
5793 _last_update_time = 0;
5797 if (playhead_cursor->current_sample () == sample) {
5801 playhead_cursor->set_position (sample);
5803 if (_session->requested_return_sample() >= 0) {
5804 _last_update_time = 0;
5808 if (!_follow_playhead || pending_visual_change.being_handled) {
5809 /* We only do this if we aren't already
5810 * handling a visual change (ie if
5811 * pending_visual_change.being_handled is
5812 * false) so that these requests don't stack
5813 * up there are too many of them to handle in
5819 if (!_stationary_playhead) {
5820 reset_x_origin_to_follow_playhead ();
5822 samplepos_t const sample = playhead_cursor->current_sample ();
5823 double target = ((double)sample - (double)current_page_samples() / 2.0);
5824 if (target <= 0.0) {
5827 // compare to EditorCursor::set_position()
5828 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5829 double const new_pos = sample_to_pixel_unrounded (target);
5830 if (rint (new_pos) != rint (old_pos)) {
5831 reset_x_origin (pixel_to_sample (new_pos));
5838 Editor::session_going_away ()
5840 _have_idled = false;
5842 _session_connections.drop_connections ();
5844 super_rapid_screen_update_connection.disconnect ();
5846 selection->clear ();
5847 cut_buffer->clear ();
5849 clicked_regionview = 0;
5850 clicked_axisview = 0;
5851 clicked_routeview = 0;
5852 entered_regionview = 0;
5854 _last_update_time = 0;
5857 playhead_cursor->hide ();
5859 /* rip everything out of the list displays */
5863 _route_groups->clear ();
5865 /* do this first so that deleting a track doesn't reset cms to null
5866 and thus cause a leak.
5869 if (current_mixer_strip) {
5870 if (current_mixer_strip->get_parent() != 0) {
5871 global_hpacker.remove (*current_mixer_strip);
5873 delete current_mixer_strip;
5874 current_mixer_strip = 0;
5877 /* delete all trackviews */
5879 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5882 track_views.clear ();
5884 nudge_clock->set_session (0);
5886 editor_list_button.set_active(false);
5887 editor_list_button.set_sensitive(false);
5889 /* clear tempo/meter rulers */
5890 remove_metric_marks ();
5891 clear_marker_display ();
5897 stop_step_editing ();
5901 /* get rid of any existing editor mixer strip */
5903 WindowTitle title(Glib::get_application_name());
5904 title += _("Editor");
5906 own_window()->set_title (title.get_string());
5909 SessionHandlePtr::session_going_away ();
5913 Editor::trigger_script (int i)
5915 LuaInstance::instance()-> call_action (i);
5919 Editor::show_editor_list (bool yn)
5922 _editor_list_vbox.show ();
5924 _editor_list_vbox.hide ();
5929 Editor::change_region_layering_order (bool from_context_menu)
5931 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5933 if (!clicked_routeview) {
5934 if (layering_order_editor) {
5935 layering_order_editor->hide ();
5940 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5946 boost::shared_ptr<Playlist> pl = track->playlist();
5952 if (layering_order_editor == 0) {
5953 layering_order_editor = new RegionLayeringOrderEditor (*this);
5956 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5957 layering_order_editor->maybe_present ();
5961 Editor::update_region_layering_order_editor ()
5963 if (layering_order_editor && layering_order_editor->is_visible ()) {
5964 change_region_layering_order (true);
5969 Editor::setup_fade_images ()
5971 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5972 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5973 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5974 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5975 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5977 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5978 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5979 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5980 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5981 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5985 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5987 Editor::action_menu_item (std::string const & name)
5989 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5992 return *manage (a->create_menu_item ());
5996 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5998 EventBox* b = manage (new EventBox);
5999 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6000 Label* l = manage (new Label (name));
6004 _the_notebook.append_page (widget, *b);
6008 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6010 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6011 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6014 if (ev->type == GDK_2BUTTON_PRESS) {
6016 /* double-click on a notebook tab shrinks or expands the notebook */
6018 if (_notebook_shrunk) {
6019 if (pre_notebook_shrink_pane_width) {
6020 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6022 _notebook_shrunk = false;
6024 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6026 /* this expands the LHS of the edit pane to cover the notebook
6027 PAGE but leaves the tabs visible.
6029 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6030 _notebook_shrunk = true;
6038 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6040 using namespace Menu_Helpers;
6042 MenuList& items = _control_point_context_menu.items ();
6045 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6046 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6047 if (!can_remove_control_point (item)) {
6048 items.back().set_sensitive (false);
6051 _control_point_context_menu.popup (event->button.button, event->button.time);
6055 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6057 using namespace Menu_Helpers;
6059 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6064 /* We need to get the selection here and pass it to the operations, since
6065 popping up the menu will cause a region leave event which clears
6066 entered_regionview. */
6068 MidiRegionView& mrv = note->region_view();
6069 const RegionSelection rs = get_regions_from_selection_and_entered ();
6070 const uint32_t sel_size = mrv.selection_size ();
6072 MenuList& items = _note_context_menu.items();
6076 items.push_back(MenuElem(_("Delete"),
6077 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6080 items.push_back(MenuElem(_("Edit..."),
6081 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6082 if (sel_size != 1) {
6083 items.back().set_sensitive (false);
6086 items.push_back(MenuElem(_("Transpose..."),
6087 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6090 items.push_back(MenuElem(_("Legatize"),
6091 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6093 items.back().set_sensitive (false);
6096 items.push_back(MenuElem(_("Quantize..."),
6097 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6099 items.push_back(MenuElem(_("Remove Overlap"),
6100 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6102 items.back().set_sensitive (false);
6105 items.push_back(MenuElem(_("Transform..."),
6106 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6108 _note_context_menu.popup (event->button.button, event->button.time);
6112 Editor::zoom_vertical_modifier_released()
6114 _stepping_axis_view = 0;
6118 Editor::ui_parameter_changed (string parameter)
6120 if (parameter == "icon-set") {
6121 while (!_cursor_stack.empty()) {
6122 _cursor_stack.pop_back();
6124 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6125 _cursor_stack.push_back(_cursors->grabber);
6126 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6127 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6129 } else if (parameter == "draggable-playhead") {
6130 if (_verbose_cursor) {
6131 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6137 Editor::use_own_window (bool and_fill_it)
6139 bool new_window = !own_window();
6141 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6143 if (win && new_window) {
6144 win->set_name ("EditorWindow");
6146 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6148 // win->signal_realize().connect (*this, &Editor::on_realize);
6149 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6150 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6151 win->set_data ("ardour-bindings", bindings);
6156 DisplaySuspender ds;
6157 contents().show_all ();
6159 /* XXX: this is a bit unfortunate; it would probably
6160 be nicer if we could just call show () above rather
6161 than needing the show_all ()
6164 /* re-hide stuff if necessary */
6165 editor_list_button_toggled ();
6166 parameter_changed ("show-summary");
6167 parameter_changed ("show-group-tabs");
6168 parameter_changed ("show-zoom-tools");
6170 /* now reset all audio_time_axis heights, because widgets might need
6176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6177 tv = (static_cast<TimeAxisView*>(*i));
6178 tv->reset_height ();
6181 if (current_mixer_strip) {
6182 current_mixer_strip->hide_things ();
6183 current_mixer_strip->parameter_changed ("mixer-element-visibility");