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 #define COMBO_TRIANGLE_WIDTH 10 // as-measured. was 25: ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
229 : PublicEditor (global_hpacker)
230 , editor_mixer_strip_width (Wide)
231 , constructed (false)
232 , _playlist_selector (0)
234 , no_save_visual (false)
235 , _leftmost_sample (0)
236 , samples_per_pixel (2048)
237 , zoom_focus (ZoomFocusPlayhead)
238 , mouse_mode (MouseObject)
239 , pre_internal_grid_type (GridTypeBeat)
240 , pre_internal_snap_mode (SnapOff)
241 , internal_grid_type (GridTypeBeat)
242 , internal_snap_mode (SnapOff)
243 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
244 , _notebook_shrunk (false)
245 , location_marker_color (0)
246 , location_range_color (0)
247 , location_loop_color (0)
248 , location_punch_color (0)
249 , location_cd_marker_color (0)
251 , _show_marker_lines (false)
252 , clicked_axisview (0)
253 , clicked_routeview (0)
254 , clicked_regionview (0)
255 , clicked_selection (0)
256 , clicked_control_point (0)
257 , button_release_can_deselect (true)
258 , _mouse_changed_selection (false)
259 , region_edit_menu_split_item (0)
260 , region_edit_menu_split_multichannel_item (0)
261 , track_region_edit_playlist_menu (0)
262 , track_edit_playlist_submenu (0)
263 , track_selection_edit_playlist_submenu (0)
264 , _popup_region_menu_item (0)
266 , _track_canvas_viewport (0)
267 , within_track_canvas (false)
268 , _verbose_cursor (0)
272 , range_marker_group (0)
273 , transport_marker_group (0)
274 , cd_marker_group (0)
275 , _time_markers_group (0)
276 , hv_scroll_group (0)
278 , cursor_scroll_group (0)
279 , no_scroll_group (0)
280 , _trackview_group (0)
281 , _drag_motion_group (0)
282 , _canvas_drop_zone (0)
283 , no_ruler_shown_update (false)
284 , ruler_grabbed_widget (0)
286 , minsec_mark_interval (0)
287 , minsec_mark_modulo (0)
289 , timecode_ruler_scale (timecode_show_many_hours)
290 , timecode_mark_modulo (0)
291 , timecode_nmarks (0)
292 , _samples_ruler_interval (0)
293 , bbt_ruler_scale (bbt_show_many)
296 , bbt_bar_helper_on (0)
297 , bbt_accent_modulo (0)
302 , visible_timebars (0)
303 , editor_ruler_menu (0)
307 , range_marker_bar (0)
308 , transport_marker_bar (0)
310 , minsec_label (_("Mins:Secs"))
311 , bbt_label (_("Bars:Beats"))
312 , timecode_label (_("Timecode"))
313 , samples_label (_("Samples"))
314 , tempo_label (_("Tempo"))
315 , meter_label (_("Meter"))
316 , mark_label (_("Location Markers"))
317 , range_mark_label (_("Range Markers"))
318 , transport_mark_label (_("Loop/Punch Ranges"))
319 , cd_mark_label (_("CD Markers"))
320 , videotl_label (_("Video Timeline"))
323 , playhead_cursor (0)
324 , _region_boundary_cache_dirty (true)
325 , edit_packer (4, 4, true)
326 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
327 , horizontal_adjustment (0.0, 0.0, 1e16)
328 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
329 , controls_layout (unused_adjustment, vertical_adjustment)
330 , _scroll_callbacks (0)
331 , _visible_canvas_width (0)
332 , _visible_canvas_height (0)
333 , _full_canvas_height (0)
334 , edit_controls_left_menu (0)
335 , edit_controls_right_menu (0)
336 , visual_change_queued(false)
337 , _last_update_time (0)
338 , _err_screen_engine (0)
339 , cut_buffer_start (0)
340 , cut_buffer_length (0)
341 , button_bindings (0)
342 , last_paste_pos (-1)
345 , current_interthread_info (0)
346 , analysis_window (0)
347 , select_new_marker (false)
349 , scrubbing_direction (0)
350 , scrub_reversals (0)
351 , scrub_reverse_distance (0)
352 , have_pending_keyboard_selection (false)
353 , pending_keyboard_selection_start (0)
354 , _grid_type (GridTypeBeat)
355 , _snap_mode (SnapOff)
356 , ignore_gui_changes (false)
357 , _drags (new DragManager (this))
359 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
360 , _dragging_playhead (false)
361 , _dragging_edit_point (false)
362 , _follow_playhead (true)
363 , _stationary_playhead (false)
366 , global_rect_group (0)
367 , time_line_group (0)
368 , tempo_marker_menu (0)
369 , meter_marker_menu (0)
371 , range_marker_menu (0)
372 , transport_marker_menu (0)
373 , new_transport_marker_menu (0)
375 , marker_menu_item (0)
376 , bbt_beat_subdivision (4)
377 , _visible_track_count (-1)
378 , toolbar_selection_clock_table (2,3)
379 , automation_mode_button (_("mode"))
380 , selection (new Selection (this, true))
381 , cut_buffer (new Selection (this, false))
382 , _selection_memento (new SelectionMemento())
383 , _all_region_actions_sensitized (false)
384 , _ignore_region_action (false)
385 , _last_region_menu_was_main (false)
386 , _track_selection_change_without_scroll (false)
387 , _editor_track_selection_change_without_scroll (false)
388 , cd_marker_bar_drag_rect (0)
389 , range_bar_drag_rect (0)
390 , transport_bar_drag_rect (0)
391 , transport_bar_range_rect (0)
392 , transport_bar_preroll_rect (0)
393 , transport_bar_postroll_rect (0)
394 , transport_loop_range_rect (0)
395 , transport_punch_range_rect (0)
396 , transport_punchin_line (0)
397 , transport_punchout_line (0)
398 , transport_preroll_rect (0)
399 , transport_postroll_rect (0)
401 , rubberband_rect (0)
407 , autoscroll_horizontal_allowed (false)
408 , autoscroll_vertical_allowed (false)
410 , autoscroll_widget (0)
411 , show_gain_after_trim (false)
412 , selection_op_cmd_depth (0)
413 , selection_op_history_it (0)
414 , no_save_instant (false)
416 , current_mixer_strip (0)
417 , show_editor_mixer_when_tracks_arrive (false)
418 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
419 , current_stepping_trackview (0)
420 , last_track_height_step_timestamp (0)
422 , entered_regionview (0)
423 , clear_entered_track (false)
424 , _edit_point (EditAtMouse)
425 , meters_running (false)
427 , _have_idled (false)
428 , resize_idle_id (-1)
429 , _pending_resize_amount (0)
430 , _pending_resize_view (0)
431 , _pending_locate_request (false)
432 , _pending_initial_locate (false)
436 , layering_order_editor (0)
437 , _last_cut_copy_source_track (0)
438 , _region_selection_change_updates_region_list (true)
440 , _following_mixer_selection (false)
441 , _control_point_toggled_on_press (false)
442 , _stepping_axis_view (0)
443 , quantize_dialog (0)
444 , _main_menu_disabler (0)
445 , myactions (X_("editor"))
447 /* we are a singleton */
449 PublicEditor::_instance = this;
453 last_event_time.tv_sec = 0;
454 last_event_time.tv_usec = 0;
456 selection_op_history.clear();
459 grid_type_strings = I18N (_grid_type_strings);
460 zoom_focus_strings = I18N (_zoom_focus_strings);
461 edit_mode_strings = I18N (_edit_mode_strings);
462 edit_point_strings = I18N (_edit_point_strings);
463 #ifdef USE_RUBBERBAND
464 rb_opt_strings = I18N (_rb_opt_strings);
468 build_edit_mode_menu();
469 build_zoom_focus_menu();
470 build_track_count_menu();
471 build_grid_type_menu();
472 build_edit_point_menu();
474 location_marker_color = UIConfiguration::instance().color ("location marker");
475 location_range_color = UIConfiguration::instance().color ("location range");
476 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
477 location_loop_color = UIConfiguration::instance().color ("location loop");
478 location_punch_color = UIConfiguration::instance().color ("location punch");
480 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
482 TimeAxisView::setup_sizes ();
483 ArdourMarker::setup_sizes (timebar_height);
484 TempoCurve::setup_sizes (timebar_height);
486 bbt_label.set_name ("EditorRulerLabel");
487 bbt_label.set_size_request (-1, (int)timebar_height);
488 bbt_label.set_alignment (1.0, 0.5);
489 bbt_label.set_padding (5,0);
491 bbt_label.set_no_show_all();
492 minsec_label.set_name ("EditorRulerLabel");
493 minsec_label.set_size_request (-1, (int)timebar_height);
494 minsec_label.set_alignment (1.0, 0.5);
495 minsec_label.set_padding (5,0);
496 minsec_label.hide ();
497 minsec_label.set_no_show_all();
498 timecode_label.set_name ("EditorRulerLabel");
499 timecode_label.set_size_request (-1, (int)timebar_height);
500 timecode_label.set_alignment (1.0, 0.5);
501 timecode_label.set_padding (5,0);
502 timecode_label.hide ();
503 timecode_label.set_no_show_all();
504 samples_label.set_name ("EditorRulerLabel");
505 samples_label.set_size_request (-1, (int)timebar_height);
506 samples_label.set_alignment (1.0, 0.5);
507 samples_label.set_padding (5,0);
508 samples_label.hide ();
509 samples_label.set_no_show_all();
511 tempo_label.set_name ("EditorRulerLabel");
512 tempo_label.set_size_request (-1, (int)timebar_height);
513 tempo_label.set_alignment (1.0, 0.5);
514 tempo_label.set_padding (5,0);
516 tempo_label.set_no_show_all();
518 meter_label.set_name ("EditorRulerLabel");
519 meter_label.set_size_request (-1, (int)timebar_height);
520 meter_label.set_alignment (1.0, 0.5);
521 meter_label.set_padding (5,0);
523 meter_label.set_no_show_all();
525 if (Profile->get_trx()) {
526 mark_label.set_text (_("Markers"));
528 mark_label.set_name ("EditorRulerLabel");
529 mark_label.set_size_request (-1, (int)timebar_height);
530 mark_label.set_alignment (1.0, 0.5);
531 mark_label.set_padding (5,0);
533 mark_label.set_no_show_all();
535 cd_mark_label.set_name ("EditorRulerLabel");
536 cd_mark_label.set_size_request (-1, (int)timebar_height);
537 cd_mark_label.set_alignment (1.0, 0.5);
538 cd_mark_label.set_padding (5,0);
539 cd_mark_label.hide();
540 cd_mark_label.set_no_show_all();
542 videotl_bar_height = 4;
543 videotl_label.set_name ("EditorRulerLabel");
544 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
545 videotl_label.set_alignment (1.0, 0.5);
546 videotl_label.set_padding (5,0);
547 videotl_label.hide();
548 videotl_label.set_no_show_all();
550 range_mark_label.set_name ("EditorRulerLabel");
551 range_mark_label.set_size_request (-1, (int)timebar_height);
552 range_mark_label.set_alignment (1.0, 0.5);
553 range_mark_label.set_padding (5,0);
554 range_mark_label.hide();
555 range_mark_label.set_no_show_all();
557 transport_mark_label.set_name ("EditorRulerLabel");
558 transport_mark_label.set_size_request (-1, (int)timebar_height);
559 transport_mark_label.set_alignment (1.0, 0.5);
560 transport_mark_label.set_padding (5,0);
561 transport_mark_label.hide();
562 transport_mark_label.set_no_show_all();
564 initialize_canvas ();
566 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
568 _summary = new EditorSummary (this);
570 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
571 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
573 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
575 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
576 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
578 edit_controls_vbox.set_spacing (0);
579 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
580 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
582 HBox* h = manage (new HBox);
583 _group_tabs = new EditorGroupTabs (this);
584 if (!ARDOUR::Profile->get_trx()) {
585 h->pack_start (*_group_tabs, PACK_SHRINK);
587 h->pack_start (edit_controls_vbox);
588 controls_layout.add (*h);
590 controls_layout.set_name ("EditControlsBase");
591 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
592 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
593 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
595 _cursors = new MouseCursors;
596 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
597 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
599 /* Push default cursor to ever-present bottom of cursor stack. */
600 push_canvas_cursor(_cursors->grabber);
602 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
604 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
605 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
606 pad_line_1->set_outline_color (0xFF0000FF);
612 edit_packer.set_col_spacings (0);
613 edit_packer.set_row_spacings (0);
614 edit_packer.set_homogeneous (false);
615 edit_packer.set_border_width (0);
616 edit_packer.set_name ("EditorWindow");
618 time_bars_event_box.add (time_bars_vbox);
619 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
620 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
622 /* labels for the time bars */
623 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
625 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
627 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
629 bottom_hbox.set_border_width (2);
630 bottom_hbox.set_spacing (3);
632 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
634 _route_groups = new EditorRouteGroups (this);
635 _routes = new EditorRoutes (this);
636 _regions = new EditorRegions (this);
637 _snapshots = new EditorSnapshots (this);
638 _locations = new EditorLocations (this);
639 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
641 /* these are static location signals */
643 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
644 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
645 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
647 add_notebook_page (_("Regions"), _regions->widget ());
648 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
649 add_notebook_page (_("Snapshots"), _snapshots->widget ());
650 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
651 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
653 _the_notebook.set_show_tabs (true);
654 _the_notebook.set_scrollable (true);
655 _the_notebook.popup_disable ();
656 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
657 _the_notebook.show_all ();
659 _notebook_shrunk = false;
662 /* Pick up some settings we need to cache, early */
664 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
667 settings->get_property ("notebook-shrunk", _notebook_shrunk);
670 editor_summary_pane.set_check_divider_position (true);
671 editor_summary_pane.add (edit_packer);
673 Button* summary_arrow_left = manage (new Button);
674 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
675 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
676 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
678 Button* summary_arrow_right = manage (new Button);
679 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
680 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
681 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
683 VBox* summary_arrows_left = manage (new VBox);
684 summary_arrows_left->pack_start (*summary_arrow_left);
686 VBox* summary_arrows_right = manage (new VBox);
687 summary_arrows_right->pack_start (*summary_arrow_right);
689 Frame* summary_sample = manage (new Frame);
690 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
692 summary_sample->add (*_summary);
693 summary_sample->show ();
695 _summary_hbox.pack_start (*summary_arrows_left, false, false);
696 _summary_hbox.pack_start (*summary_sample, true, true);
697 _summary_hbox.pack_start (*summary_arrows_right, false, false);
699 if (!ARDOUR::Profile->get_trx()) {
700 editor_summary_pane.add (_summary_hbox);
703 edit_pane.set_check_divider_position (true);
704 edit_pane.add (editor_summary_pane);
705 if (!ARDOUR::Profile->get_trx()) {
706 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
707 _editor_list_vbox.pack_start (_the_notebook);
708 edit_pane.add (_editor_list_vbox);
709 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
712 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
713 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
716 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
717 /* initial allocation is 90% to canvas, 10% to notebook */
720 edit_pane.set_divider (0, fract);
722 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
723 /* initial allocation is 90% to canvas, 10% to summary */
726 editor_summary_pane.set_divider (0, fract);
728 global_vpacker.set_spacing (2);
729 global_vpacker.set_border_width (0);
731 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
733 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
734 ebox->set_name("EditorWindow");
735 ebox->add (toolbar_hbox);
737 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
738 epane_box->set_name("EditorWindow");
739 epane_box->add (edit_pane);
741 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
742 epane_box2->set_name("EditorWindow");
743 epane_box2->add (global_vpacker);
745 global_vpacker.pack_start (*ebox, false, false);
746 global_vpacker.pack_start (*epane_box, true, true);
747 global_hpacker.pack_start (*epane_box2, true, true);
749 /* need to show the "contents" widget so that notebook will show if tab is switched to
752 global_hpacker.show ();
754 /* register actions now so that set_state() can find them and set toggles/checks etc */
761 _playlist_selector = new PlaylistSelector();
762 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
764 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
768 nudge_forward_button.set_name ("nudge button");
769 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
771 nudge_backward_button.set_name ("nudge button");
772 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
774 fade_context_menu.set_name ("ArdourContextMenu");
776 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
778 /* allow external control surfaces/protocols to do various things */
780 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
781 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
782 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
783 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
784 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
785 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
786 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
787 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
788 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
789 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
790 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
791 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
792 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
793 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
795 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
796 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
797 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
798 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
801 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
805 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
807 /* problematic: has to return a value and thus cannot be x-thread */
809 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
811 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
812 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
814 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
816 _ignore_region_action = false;
817 _last_region_menu_was_main = false;
818 _popup_region_menu_item = 0;
820 _show_marker_lines = false;
822 /* Button bindings */
824 button_bindings = new Bindings ("editor-mouse");
826 XMLNode* node = button_settings();
828 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
829 button_bindings->load_operation (**i);
835 /* grab current parameter state */
836 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
837 UIConfiguration::instance().map_parameters (pc);
839 setup_fade_images ();
841 set_grid_to (GridTypeNone);
848 delete button_bindings;
850 delete _route_groups;
851 delete _track_canvas_viewport;
854 delete _verbose_cursor;
855 delete quantize_dialog;
861 delete _playlist_selector;
862 delete _time_info_box;
867 LuaInstance::destroy_instance ();
869 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
872 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
875 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
881 Editor::button_settings () const
883 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
884 XMLNode* node = find_named_node (*settings, X_("Buttons"));
887 node = new XMLNode (X_("Buttons"));
894 Editor::get_smart_mode () const
896 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
900 Editor::catch_vanishing_regionview (RegionView *rv)
902 /* note: the selection will take care of the vanishing
903 audioregionview by itself.
906 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
910 if (clicked_regionview == rv) {
911 clicked_regionview = 0;
914 if (entered_regionview == rv) {
915 set_entered_regionview (0);
918 if (!_all_region_actions_sensitized) {
919 sensitize_all_region_actions (true);
924 Editor::set_entered_regionview (RegionView* rv)
926 if (rv == entered_regionview) {
930 if (entered_regionview) {
931 entered_regionview->exited ();
934 entered_regionview = rv;
936 if (entered_regionview != 0) {
937 entered_regionview->entered ();
940 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
941 /* This RegionView entry might have changed what region actions
942 are allowed, so sensitize them all in case a key is pressed.
944 sensitize_all_region_actions (true);
949 Editor::set_entered_track (TimeAxisView* tav)
952 entered_track->exited ();
958 entered_track->entered ();
963 Editor::instant_save ()
965 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
970 _session->add_instant_xml(get_state());
972 Config->add_instant_xml(get_state());
977 Editor::control_vertical_zoom_in_all ()
979 tav_zoom_smooth (false, true);
983 Editor::control_vertical_zoom_out_all ()
985 tav_zoom_smooth (true, true);
989 Editor::control_vertical_zoom_in_selected ()
991 tav_zoom_smooth (false, false);
995 Editor::control_vertical_zoom_out_selected ()
997 tav_zoom_smooth (true, false);
1001 Editor::control_view (uint32_t view)
1003 goto_visual_state (view);
1007 Editor::control_unselect ()
1009 selection->clear_tracks ();
1013 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1015 TimeAxisView* tav = time_axis_view_from_stripable (s);
1019 case Selection::Add:
1020 selection->add (tav);
1022 case Selection::Toggle:
1023 selection->toggle (tav);
1025 case Selection::Extend:
1027 case Selection::Set:
1028 selection->set (tav);
1032 selection->clear_tracks ();
1037 Editor::control_step_tracks_up ()
1039 scroll_tracks_up_line ();
1043 Editor::control_step_tracks_down ()
1045 scroll_tracks_down_line ();
1049 Editor::control_scroll (float fraction)
1051 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1057 double step = fraction * current_page_samples();
1060 _control_scroll_target is an optional<T>
1062 it acts like a pointer to an samplepos_t, with
1063 a operator conversion to boolean to check
1064 that it has a value could possibly use
1065 playhead_cursor->current_sample to store the
1066 value and a boolean in the class to know
1067 when it's out of date
1070 if (!_control_scroll_target) {
1071 _control_scroll_target = _session->transport_sample();
1072 _dragging_playhead = true;
1075 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1076 *_control_scroll_target = 0;
1077 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1078 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1080 *_control_scroll_target += (samplepos_t) trunc (step);
1083 /* move visuals, we'll catch up with it later */
1085 playhead_cursor->set_position (*_control_scroll_target);
1086 UpdateAllTransportClocks (*_control_scroll_target);
1088 if (*_control_scroll_target > (current_page_samples() / 2)) {
1089 /* try to center PH in window */
1090 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1096 Now we do a timeout to actually bring the session to the right place
1097 according to the playhead. This is to avoid reading disk buffers on every
1098 call to control_scroll, which is driven by ScrollTimeline and therefore
1099 probably by a control surface wheel which can generate lots of events.
1101 /* cancel the existing timeout */
1103 control_scroll_connection.disconnect ();
1105 /* add the next timeout */
1107 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1111 Editor::deferred_control_scroll (samplepos_t /*target*/)
1113 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1114 // reset for next stream
1115 _control_scroll_target = boost::none;
1116 _dragging_playhead = false;
1121 Editor::access_action (const std::string& action_group, const std::string& action_item)
1127 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1130 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1138 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1140 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1144 Editor::on_realize ()
1148 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1154 Editor::start_lock_event_timing ()
1156 /* check if we should lock the GUI every 30 seconds */
1158 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1162 Editor::generic_event_handler (GdkEvent* ev)
1165 case GDK_BUTTON_PRESS:
1166 case GDK_BUTTON_RELEASE:
1167 case GDK_MOTION_NOTIFY:
1169 case GDK_KEY_RELEASE:
1170 if (contents().is_mapped()) {
1171 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1187 ARDOUR_UI::instance()->reset_focus (&contents());
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (samplepos_t sample)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (sample);
1235 playhead_cursor->set_position (sample);
1239 Editor::center_screen (samplepos_t sample)
1241 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1247 center_screen_internal (sample, page);
1252 Editor::center_screen_internal (samplepos_t sample, float page)
1256 if (sample > page) {
1257 sample -= (samplepos_t) page;
1262 reset_x_origin (sample);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1271 if (!own_window()) {
1276 bool dirty = _session->dirty();
1278 string session_name;
1280 if (_session->snap_name() != _session->name()) {
1281 session_name = _session->snap_name();
1283 session_name = _session->name();
1287 session_name = "*" + session_name;
1290 WindowTitle title(session_name);
1291 title += S_("Window|Editor");
1292 title += Glib::get_application_name();
1293 own_window()->set_title (title.get_string());
1295 /* ::session_going_away() will have taken care of it */
1300 Editor::set_session (Session *t)
1302 SessionHandlePtr::set_session (t);
1308 //initialize _leftmost_sample to the extents of the session
1309 //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
1310 _leftmost_sample = session_gui_extents().first;
1312 _playlist_selector->set_session (_session);
1313 nudge_clock->set_session (_session);
1314 _summary->set_session (_session);
1315 _group_tabs->set_session (_session);
1316 _route_groups->set_session (_session);
1317 _regions->set_session (_session);
1318 _snapshots->set_session (_session);
1319 _routes->set_session (_session);
1320 _locations->set_session (_session);
1321 _time_info_box->set_session (_session);
1323 if (rhythm_ferret) {
1324 rhythm_ferret->set_session (_session);
1327 if (analysis_window) {
1328 analysis_window->set_session (_session);
1332 sfbrowser->set_session (_session);
1335 compute_fixed_ruler_scale ();
1337 /* Make sure we have auto loop and auto punch ranges */
1339 Location* loc = _session->locations()->auto_loop_location();
1341 loc->set_name (_("Loop"));
1344 loc = _session->locations()->auto_punch_location();
1347 loc->set_name (_("Punch"));
1350 refresh_location_display ();
1352 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1353 the selected Marker; this needs the LocationMarker list to be available.
1355 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1356 set_state (*node, Stateful::loading_state_version);
1358 /* catch up on selection state, etc. */
1361 sc.add (Properties::selected);
1362 presentation_info_changed (sc);
1364 /* catch up with the playhead */
1366 _session->request_locate (playhead_cursor->current_sample ());
1367 _pending_initial_locate = true;
1371 /* These signals can all be emitted by a non-GUI thread. Therefore the
1372 handlers for them must not attempt to directly interact with the GUI,
1373 but use PBD::Signal<T>::connect() which accepts an event loop
1374 ("context") where the handler will be asked to run.
1377 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1378 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1379 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1380 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1381 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1382 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1383 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1384 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1385 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1386 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1387 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1388 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1389 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1390 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1391 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1392 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1394 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1395 playhead_cursor->show ();
1397 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1398 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1399 snapped_cursor->show ();
1401 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1402 Config->map_parameters (pc);
1403 _session->config.map_parameters (pc);
1405 restore_ruler_visibility ();
1406 //tempo_map_changed (PropertyChange (0));
1407 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1409 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1410 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1413 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1414 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1417 /* register for undo history */
1418 _session->register_with_memento_command_factory(id(), this);
1419 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1421 LuaInstance::instance()->set_session(_session);
1423 start_updating_meters ();
1427 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1429 using namespace Menu_Helpers;
1431 void (Editor::*emf)(FadeShape);
1432 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1435 images = &_xfade_in_images;
1436 emf = &Editor::set_fade_in_shape;
1438 images = &_xfade_out_images;
1439 emf = &Editor::set_fade_out_shape;
1444 _("Linear (for highly correlated material)"),
1445 *(*images)[FadeLinear],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 _("Constant power"),
1455 *(*images)[FadeConstantPower],
1456 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1459 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1464 *(*images)[FadeSymmetric],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1469 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 *(*images)[FadeSlow],
1475 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeFast],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 /** Pop up a context menu for when the user clicks on a start crossfade */
1492 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1494 using namespace Menu_Helpers;
1495 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1500 MenuList& items (xfade_in_context_menu.items());
1503 if (arv->audio_region()->fade_in_active()) {
1504 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1506 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1509 items.push_back (SeparatorElem());
1510 fill_xfade_menu (items, true);
1512 xfade_in_context_menu.popup (button, time);
1515 /** Pop up a context menu for when the user clicks on an end crossfade */
1517 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1519 using namespace Menu_Helpers;
1520 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1525 MenuList& items (xfade_out_context_menu.items());
1528 if (arv->audio_region()->fade_out_active()) {
1529 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1531 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1534 items.push_back (SeparatorElem());
1535 fill_xfade_menu (items, false);
1537 xfade_out_context_menu.popup (button, time);
1541 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1543 using namespace Menu_Helpers;
1544 Menu* (Editor::*build_menu_function)();
1547 switch (item_type) {
1549 case RegionViewName:
1550 case RegionViewNameHighlight:
1551 case LeftFrameHandle:
1552 case RightFrameHandle:
1553 if (with_selection) {
1554 build_menu_function = &Editor::build_track_selection_context_menu;
1556 build_menu_function = &Editor::build_track_region_context_menu;
1561 if (with_selection) {
1562 build_menu_function = &Editor::build_track_selection_context_menu;
1564 build_menu_function = &Editor::build_track_context_menu;
1569 if (clicked_routeview->track()) {
1570 build_menu_function = &Editor::build_track_context_menu;
1572 build_menu_function = &Editor::build_track_bus_context_menu;
1577 /* probably shouldn't happen but if it does, we don't care */
1581 menu = (this->*build_menu_function)();
1582 menu->set_name ("ArdourContextMenu");
1584 /* now handle specific situations */
1586 switch (item_type) {
1588 case RegionViewName:
1589 case RegionViewNameHighlight:
1590 case LeftFrameHandle:
1591 case RightFrameHandle:
1592 if (!with_selection) {
1593 if (region_edit_menu_split_item) {
1594 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1595 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1597 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1600 if (region_edit_menu_split_multichannel_item) {
1601 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1602 region_edit_menu_split_multichannel_item->set_sensitive (true);
1604 region_edit_menu_split_multichannel_item->set_sensitive (false);
1617 /* probably shouldn't happen but if it does, we don't care */
1621 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1623 /* Bounce to disk */
1625 using namespace Menu_Helpers;
1626 MenuList& edit_items = menu->items();
1628 edit_items.push_back (SeparatorElem());
1630 switch (clicked_routeview->audio_track()->freeze_state()) {
1631 case AudioTrack::NoFreeze:
1632 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1635 case AudioTrack::Frozen:
1636 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1639 case AudioTrack::UnFrozen:
1640 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1646 if (item_type == StreamItem && clicked_routeview) {
1647 clicked_routeview->build_underlay_menu(menu);
1650 /* When the region menu is opened, we setup the actions so that they look right
1653 sensitize_the_right_region_actions (false);
1654 _last_region_menu_was_main = false;
1656 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1657 menu->popup (button, time);
1661 Editor::build_track_context_menu ()
1663 using namespace Menu_Helpers;
1665 MenuList& edit_items = track_context_menu.items();
1668 add_dstream_context_items (edit_items);
1669 return &track_context_menu;
1673 Editor::build_track_bus_context_menu ()
1675 using namespace Menu_Helpers;
1677 MenuList& edit_items = track_context_menu.items();
1680 add_bus_context_items (edit_items);
1681 return &track_context_menu;
1685 Editor::build_track_region_context_menu ()
1687 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_region_context_menu.items();
1691 /* we've just cleared the track region context menu, so the menu that these
1692 two items were on will have disappeared; stop them dangling.
1694 region_edit_menu_split_item = 0;
1695 region_edit_menu_split_multichannel_item = 0;
1697 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1700 boost::shared_ptr<Track> tr;
1701 boost::shared_ptr<Playlist> pl;
1703 if ((tr = rtv->track())) {
1704 add_region_context_items (edit_items, tr);
1708 add_dstream_context_items (edit_items);
1710 return &track_region_context_menu;
1714 Editor::loudness_analyze_region_selection ()
1719 Selection& s (PublicEditor::instance ().get_selection ());
1720 RegionSelection ars = s.regions;
1721 ARDOUR::AnalysisGraph ag (_session);
1722 samplecnt_t total_work = 0;
1724 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1725 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1729 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1732 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1733 total_work += arv->region ()->length ();
1736 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1738 ag.set_total_samples (total_work);
1739 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1742 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1743 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1747 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1751 ag.analyze_region (ar);
1754 if (!ag.canceled ()) {
1755 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1761 Editor::loudness_analyze_range_selection ()
1766 Selection& s (PublicEditor::instance ().get_selection ());
1767 TimeSelection ts = s.time;
1768 ARDOUR::AnalysisGraph ag (_session);
1769 samplecnt_t total_work = 0;
1771 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1772 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1776 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1780 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1781 total_work += j->length ();
1785 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1787 ag.set_total_samples (total_work);
1788 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1791 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1792 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1796 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1800 ag.analyze_range (rui->route (), pl, ts);
1803 if (!ag.canceled ()) {
1804 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1810 Editor::spectral_analyze_region_selection ()
1812 if (analysis_window == 0) {
1813 analysis_window = new AnalysisWindow();
1816 analysis_window->set_session(_session);
1818 analysis_window->show_all();
1821 analysis_window->set_regionmode();
1822 analysis_window->analyze();
1824 analysis_window->present();
1828 Editor::spectral_analyze_range_selection()
1830 if (analysis_window == 0) {
1831 analysis_window = new AnalysisWindow();
1834 analysis_window->set_session(_session);
1836 analysis_window->show_all();
1839 analysis_window->set_rangemode();
1840 analysis_window->analyze();
1842 analysis_window->present();
1846 Editor::build_track_selection_context_menu ()
1848 using namespace Menu_Helpers;
1849 MenuList& edit_items = track_selection_context_menu.items();
1850 edit_items.clear ();
1852 add_selection_context_items (edit_items);
1853 // edit_items.push_back (SeparatorElem());
1854 // add_dstream_context_items (edit_items);
1856 return &track_selection_context_menu;
1860 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1862 using namespace Menu_Helpers;
1864 /* OK, stick the region submenu at the top of the list, and then add
1868 RegionSelection rs = get_regions_from_selection_and_entered ();
1870 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1872 if (_popup_region_menu_item == 0) {
1873 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1874 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1875 _popup_region_menu_item->show ();
1877 _popup_region_menu_item->set_label (menu_item_name);
1880 /* No layering allowed in later is higher layering model */
1881 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1882 if (act && Config->get_layer_model() == LaterHigher) {
1883 act->set_sensitive (false);
1885 act->set_sensitive (true);
1888 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1890 edit_items.push_back (*_popup_region_menu_item);
1891 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1892 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1894 edit_items.push_back (SeparatorElem());
1897 /** Add context menu items relevant to selection ranges.
1898 * @param edit_items List to add the items to.
1901 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1903 using namespace Menu_Helpers;
1905 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1906 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1913 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1915 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (
1919 _("Move Range Start to Previous Region Boundary"),
1920 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1924 edit_items.push_back (
1926 _("Move Range Start to Next Region Boundary"),
1927 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1931 edit_items.push_back (
1933 _("Move Range End to Previous Region Boundary"),
1934 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1938 edit_items.push_back (
1940 _("Move Range End to Next Region Boundary"),
1941 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1945 edit_items.push_back (SeparatorElem());
1946 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1947 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1954 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1955 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1960 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1962 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1964 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1966 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1967 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1968 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1969 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1970 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1971 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1977 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1979 using namespace Menu_Helpers;
1983 Menu *play_menu = manage (new Menu);
1984 MenuList& play_items = play_menu->items();
1985 play_menu->set_name ("ArdourContextMenu");
1987 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1988 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1989 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1990 play_items.push_back (SeparatorElem());
1991 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1993 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1997 Menu *select_menu = manage (new Menu);
1998 MenuList& select_items = select_menu->items();
1999 select_menu->set_name ("ArdourContextMenu");
2001 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2002 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2003 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2004 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2005 select_items.push_back (SeparatorElem());
2006 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2007 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2008 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2009 select_items.push_back (SeparatorElem());
2010 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2011 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2012 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2013 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2014 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2015 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2016 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2018 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2022 Menu *cutnpaste_menu = manage (new Menu);
2023 MenuList& cutnpaste_items = cutnpaste_menu->items();
2024 cutnpaste_menu->set_name ("ArdourContextMenu");
2026 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2027 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2028 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2030 cutnpaste_items.push_back (SeparatorElem());
2032 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2033 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2035 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2037 /* Adding new material */
2039 edit_items.push_back (SeparatorElem());
2040 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2041 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2045 Menu *nudge_menu = manage (new Menu());
2046 MenuList& nudge_items = nudge_menu->items();
2047 nudge_menu->set_name ("ArdourContextMenu");
2049 edit_items.push_back (SeparatorElem());
2050 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2051 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2052 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2053 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2055 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2059 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2061 using namespace Menu_Helpers;
2065 Menu *play_menu = manage (new Menu);
2066 MenuList& play_items = play_menu->items();
2067 play_menu->set_name ("ArdourContextMenu");
2069 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2070 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2071 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2075 Menu *select_menu = manage (new Menu);
2076 MenuList& select_items = select_menu->items();
2077 select_menu->set_name ("ArdourContextMenu");
2079 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2080 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2081 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2082 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2083 select_items.push_back (SeparatorElem());
2084 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2085 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2086 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2087 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2089 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2093 Menu *cutnpaste_menu = manage (new Menu);
2094 MenuList& cutnpaste_items = cutnpaste_menu->items();
2095 cutnpaste_menu->set_name ("ArdourContextMenu");
2097 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2098 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2099 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2101 Menu *nudge_menu = manage (new Menu());
2102 MenuList& nudge_items = nudge_menu->items();
2103 nudge_menu->set_name ("ArdourContextMenu");
2105 edit_items.push_back (SeparatorElem());
2106 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2107 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2108 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2109 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2111 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2115 Editor::grid_type() const
2121 Editor::grid_musical() const
2123 switch (_grid_type) {
2124 case GridTypeBeatDiv32:
2125 case GridTypeBeatDiv28:
2126 case GridTypeBeatDiv24:
2127 case GridTypeBeatDiv20:
2128 case GridTypeBeatDiv16:
2129 case GridTypeBeatDiv14:
2130 case GridTypeBeatDiv12:
2131 case GridTypeBeatDiv10:
2132 case GridTypeBeatDiv8:
2133 case GridTypeBeatDiv7:
2134 case GridTypeBeatDiv6:
2135 case GridTypeBeatDiv5:
2136 case GridTypeBeatDiv4:
2137 case GridTypeBeatDiv3:
2138 case GridTypeBeatDiv2:
2144 case GridTypeMinSec:
2145 case GridTypeSamples:
2152 Editor::grid_nonmusical() const
2154 switch (_grid_type) {
2156 case GridTypeMinSec:
2157 case GridTypeSamples:
2159 case GridTypeBeatDiv32:
2160 case GridTypeBeatDiv28:
2161 case GridTypeBeatDiv24:
2162 case GridTypeBeatDiv20:
2163 case GridTypeBeatDiv16:
2164 case GridTypeBeatDiv14:
2165 case GridTypeBeatDiv12:
2166 case GridTypeBeatDiv10:
2167 case GridTypeBeatDiv8:
2168 case GridTypeBeatDiv7:
2169 case GridTypeBeatDiv6:
2170 case GridTypeBeatDiv5:
2171 case GridTypeBeatDiv4:
2172 case GridTypeBeatDiv3:
2173 case GridTypeBeatDiv2:
2182 Editor::snap_mode() const
2188 Editor::set_grid_to (GridType gt)
2190 if (_grid_type == gt) { //already set
2194 unsigned int grid_ind = (unsigned int)gt;
2196 if (internal_editing()) {
2197 internal_grid_type = gt;
2199 pre_internal_grid_type = gt;
2204 if (grid_ind > grid_type_strings.size() - 1) {
2206 _grid_type = (GridType)grid_ind;
2209 string str = grid_type_strings[grid_ind];
2211 if (str != grid_type_selector.get_text()) {
2212 grid_type_selector.set_text (str);
2215 //show appropriate rulers for this grid setting. (ToDo: perhaps make this optional)
2216 //Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2217 if ( grid_musical() ) {
2218 ruler_tempo_action->set_active(true);
2219 ruler_meter_action->set_active(true);
2221 ruler_bbt_action->set_active(true);
2222 ruler_timecode_action->set_active(false);
2223 ruler_minsec_action->set_active(false);
2224 ruler_samples_action->set_active(false);
2225 } else if (_grid_type == GridTypeSmpte ) {
2226 ruler_tempo_action->set_active(false);
2227 ruler_meter_action->set_active(false);
2229 ruler_bbt_action->set_active(false);
2230 ruler_timecode_action->set_active(true);
2231 ruler_minsec_action->set_active(false);
2232 ruler_samples_action->set_active(false);
2233 } else if (_grid_type == GridTypeMinSec ) {
2234 ruler_tempo_action->set_active(false);
2235 ruler_meter_action->set_active(false);
2237 ruler_bbt_action->set_active(false);
2238 ruler_timecode_action->set_active(false);
2239 ruler_minsec_action->set_active(true);
2240 ruler_samples_action->set_active(false);
2241 } else if (_grid_type == GridTypeSamples ) {
2242 ruler_tempo_action->set_active(false);
2243 ruler_meter_action->set_active(false);
2245 ruler_bbt_action->set_active(false);
2246 ruler_timecode_action->set_active(false);
2247 ruler_minsec_action->set_active(false);
2248 ruler_samples_action->set_active(true);
2253 if ( grid_musical() ) {
2254 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2255 update_tempo_based_rulers ();
2258 mark_region_boundary_cache_dirty ();
2260 redisplay_grid (false);
2262 SnapChanged (); /* EMIT SIGNAL */
2266 Editor::set_snap_mode (SnapMode mode)
2268 if (internal_editing()) {
2269 internal_snap_mode = mode;
2271 pre_internal_snap_mode = mode;
2276 if (_snap_mode == SnapOff ) {
2277 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2279 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2286 Editor::set_edit_point_preference (EditPoint ep, bool force)
2288 bool changed = (_edit_point != ep);
2291 if (Profile->get_mixbus())
2292 if (ep == EditAtSelectedMarker)
2293 ep = EditAtPlayhead;
2295 string str = edit_point_strings[(int)ep];
2296 if (str != edit_point_selector.get_text ()) {
2297 edit_point_selector.set_text (str);
2300 update_all_enter_cursors();
2302 if (!force && !changed) {
2306 const char* action=NULL;
2308 switch (_edit_point) {
2309 case EditAtPlayhead:
2310 action = "edit-at-playhead";
2312 case EditAtSelectedMarker:
2313 action = "edit-at-marker";
2316 action = "edit-at-mouse";
2320 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2322 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2326 bool in_track_canvas;
2328 if (!mouse_sample (foo, in_track_canvas)) {
2329 in_track_canvas = false;
2332 reset_canvas_action_sensitivity (in_track_canvas);
2333 sensitize_the_right_region_actions (false);
2339 Editor::set_state (const XMLNode& node, int version)
2342 PBD::Unwinder<bool> nsi (no_save_instant, true);
2345 Tabbable::set_state (node, version);
2348 if (_session && node.get_property ("playhead", ph_pos)) {
2350 playhead_cursor->set_position (ph_pos);
2352 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2353 playhead_cursor->set_position (0);
2356 playhead_cursor->set_position (0);
2359 node.get_property ("mixer-width", editor_mixer_strip_width);
2361 node.get_property ("zoom-focus", zoom_focus);
2362 zoom_focus_selection_done (zoom_focus);
2365 if (node.get_property ("zoom", z)) {
2366 /* older versions of ardour used floating point samples_per_pixel */
2367 reset_zoom (llrintf (z));
2369 reset_zoom (samples_per_pixel);
2373 if (node.get_property ("visible-track-count", cnt)) {
2374 set_visible_track_count (cnt);
2378 if (!node.get_property ("grid-type", grid_type)) {
2379 grid_type = _grid_type;
2381 set_grid_to (grid_type);
2384 if (node.get_property ("snap-mode", sm)) {
2385 snap_mode_selection_done(sm);
2386 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2387 * snap_mode_selection_done() will only mark an already active item as active
2388 * which does not trigger set_text().
2392 set_snap_mode (_snap_mode);
2395 node.get_property ("internal-grid-type", internal_grid_type);
2396 node.get_property ("internal-snap-mode", internal_snap_mode);
2397 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2398 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2401 if (node.get_property ("mouse-mode", mm_str)) {
2402 MouseMode m = str2mousemode(mm_str);
2403 set_mouse_mode (m, true);
2405 set_mouse_mode (MouseObject, true);
2409 if (node.get_property ("left-frame", lf_pos)) {
2413 reset_x_origin (lf_pos);
2417 if (node.get_property ("y-origin", y_origin)) {
2418 reset_y_origin (y_origin);
2421 if (node.get_property ("join-object-range", yn)) {
2422 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2424 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2425 tact->set_active (!yn);
2426 tact->set_active (yn);
2428 set_mouse_mode(mouse_mode, true);
2432 if (node.get_property ("edit-point", ep)) {
2433 set_edit_point_preference (ep, true);
2435 set_edit_point_preference (_edit_point);
2438 if (node.get_property ("follow-playhead", yn)) {
2439 set_follow_playhead (yn);
2442 if (node.get_property ("stationary-playhead", yn)) {
2443 set_stationary_playhead (yn);
2446 RegionListSortType sort_type;
2447 if (node.get_property ("region-list-sort-type", sort_type)) {
2448 _regions->reset_sort_type (sort_type, true);
2451 if (node.get_property ("show-editor-mixer", yn)) {
2453 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2456 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2458 /* do it twice to force the change */
2460 tact->set_active (!yn);
2461 tact->set_active (yn);
2464 if (node.get_property ("show-editor-list", yn)) {
2466 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2469 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2471 /* do it twice to force the change */
2473 tact->set_active (!yn);
2474 tact->set_active (yn);
2478 if (node.get_property (X_("editor-list-page"), el_page)) {
2479 _the_notebook.set_current_page (el_page);
2482 if (node.get_property (X_("show-marker-lines"), yn)) {
2483 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2485 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2487 tact->set_active (!yn);
2488 tact->set_active (yn);
2491 XMLNodeList children = node.children ();
2492 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2493 selection->set_state (**i, Stateful::current_state_version);
2494 _regions->set_state (**i);
2495 _locations->set_state (**i);
2498 if (node.get_property ("maximised", yn)) {
2499 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2501 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2502 bool fs = tact && tact->get_active();
2504 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2508 samplepos_t nudge_clock_value;
2509 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2510 nudge_clock->set (nudge_clock_value);
2512 nudge_clock->set_mode (AudioClock::Timecode);
2513 nudge_clock->set (_session->sample_rate() * 5, true);
2518 * Not all properties may have been in XML, but
2519 * those that are linked to a private variable may need changing
2523 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2524 yn = _follow_playhead;
2526 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2527 if (tact->get_active() != yn) {
2528 tact->set_active (yn);
2532 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2533 yn = _stationary_playhead;
2535 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2536 if (tact->get_active() != yn) {
2537 tact->set_active (yn);
2542 return LuaInstance::instance()->set_state(node);
2546 Editor::get_state ()
2548 XMLNode* node = new XMLNode (X_("Editor"));
2550 node->set_property ("id", id().to_s ());
2552 node->add_child_nocopy (Tabbable::get_state());
2554 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2555 node->set_property("notebook-shrunk", _notebook_shrunk);
2556 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2558 maybe_add_mixer_strip_width (*node);
2560 node->set_property ("zoom-focus", zoom_focus);
2562 node->set_property ("zoom", samples_per_pixel);
2563 node->set_property ("grid-type", _grid_type);
2564 node->set_property ("snap-mode", _snap_mode);
2565 node->set_property ("internal-grid-type", internal_grid_type);
2566 node->set_property ("internal-snap-mode", internal_snap_mode);
2567 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2568 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2569 node->set_property ("edit-point", _edit_point);
2570 node->set_property ("visible-track-count", _visible_track_count);
2572 node->set_property ("playhead", playhead_cursor->current_sample ());
2573 node->set_property ("left-frame", _leftmost_sample);
2574 node->set_property ("y-origin", vertical_adjustment.get_value ());
2576 node->set_property ("maximised", _maximised);
2577 node->set_property ("follow-playhead", _follow_playhead);
2578 node->set_property ("stationary-playhead", _stationary_playhead);
2579 node->set_property ("region-list-sort-type", _regions->sort_type ());
2580 node->set_property ("mouse-mode", mouse_mode);
2581 node->set_property ("join-object-range", smart_mode_action->get_active ());
2583 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2585 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2586 node->set_property (X_("show-editor-mixer"), tact->get_active());
2589 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2591 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2592 node->set_property (X_("show-editor-list"), tact->get_active());
2595 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2597 if (button_bindings) {
2598 XMLNode* bb = new XMLNode (X_("Buttons"));
2599 button_bindings->save (*bb);
2600 node->add_child_nocopy (*bb);
2603 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2605 node->add_child_nocopy (selection->get_state ());
2606 node->add_child_nocopy (_regions->get_state ());
2608 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2610 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2611 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2612 node->add_child_nocopy (_locations->get_state ());
2617 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2618 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2620 * @return pair: TimeAxisView that y is over, layer index.
2622 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2623 * in stacked or expanded region display mode, otherwise 0.
2625 std::pair<TimeAxisView *, double>
2626 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2628 if (!trackview_relative_offset) {
2629 y -= _trackview_group->canvas_origin().y;
2633 return std::make_pair ( (TimeAxisView *) 0, 0);
2636 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2638 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2645 return std::make_pair ( (TimeAxisView *) 0, 0);
2649 Editor::set_snapped_cursor_position (samplepos_t pos)
2651 if ( _edit_point == EditAtMouse ) {
2652 snapped_cursor->set_position(pos);
2657 /** Snap a position to the grid, if appropriate, taking into account current
2658 * grid settings and also the state of any snap modifier keys that may be pressed.
2659 * @param start Position to snap.
2660 * @param event Event to get current key modifier information from, or 0.
2663 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2665 if (!_session || !event) {
2669 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2670 if (_snap_mode == SnapOff) {
2671 snap_to_internal (start, direction, pref, for_mark);
2673 start.set (start.sample, 0);
2676 if (_snap_mode != SnapOff) {
2677 snap_to_internal (start, direction, pref, for_mark);
2678 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2679 /* SnapOff, but we pressed the snap_delta modifier */
2680 snap_to_internal (start, direction, pref, for_mark);
2682 start.set (start.sample, 0);
2688 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2690 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2691 start.set (start.sample, 0);
2695 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2699 check_best_snap ( samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best )
2701 samplepos_t diff = abs( test - presnap );
2702 if ( diff < dist ) {
2707 test = max_samplepos; //reset this so it doesn't get accidentally reused
2711 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2713 if (marks.empty() ) return presnap;
2719 before = after = max_samplepos;
2721 //get marks to either side of presnap
2722 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2723 while ( m != marks.end() && (m->position < presnap) ) {
2727 if (m == marks.end ()) {
2728 /* ran out of marks */
2729 before = marks.back().position;
2732 after = m->position;
2734 if (m != marks.begin ()) {
2736 before = m->position;
2739 if (before == max_samplepos && after == max_samplepos) {
2740 /* No smpte to snap to, so just don't snap */
2742 } else if (before == max_samplepos) {
2744 } else if (after == max_samplepos) {
2747 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2749 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2751 else if (direction == 0 ) {
2752 if ((presnap - before) < (after - presnap)) {
2764 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2770 _session->locations()->marks_either_side (presnap, before, after);
2772 if (before == max_samplepos && after == max_samplepos) {
2773 /* No marks to snap to, so just don't snap */
2775 } else if (before == max_samplepos) {
2777 } else if (after == max_samplepos) {
2780 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2782 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2784 } else if (direction == 0 ) {
2785 if ((presnap - before) < (after - presnap)) {
2797 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2799 const samplepos_t presnap = start.sample;
2801 samplepos_t test = max_samplepos; //for each snap, we'll use this value
2802 samplepos_t dist = max_samplepos; //this records the distance of the best snap result we've found so far
2803 samplepos_t best = max_samplepos; //this records the best snap-result we've found so far
2805 //check snap-to-marker
2806 if ( UIConfiguration::instance().get_snap_to_marks() ) {
2811 test = marker_snap_to_internal ( presnap, direction );
2812 check_best_snap(presnap, test, dist, best);
2815 //check snap-to-region-{start/end/sync}
2816 if ( UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync() ) {
2817 if (!region_boundary_cache.empty()) {
2819 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2820 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2822 if (direction > 0) {
2823 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2825 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2828 if (next != region_boundary_cache.begin ()) {
2833 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2834 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2836 if (presnap > (p + n) / 2) {
2843 check_best_snap(presnap, test, dist, best);
2847 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone) ) {
2849 //if SnapToGrid is selected, the user wants to prioritize the music grid
2850 //in this case we should reset the best distance, so Grid will prevail
2851 dist = max_samplepos;
2853 test = snap_to_grid (grid_marks, presnap, direction);
2854 check_best_snap(presnap, test, dist, best);
2857 //now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2858 //this also helps to avoid snapping to somewhere the user can't see. ( i.e.: I clicked on a region and it disappeared!! )
2859 //ToDo: perhaps this should only occur if EditPointMouse?
2860 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2862 start.set (best, 0);
2864 } else if (presnap > best) {
2865 if (presnap > (best+ snap_threshold_s)) {
2868 } else if (presnap < best) {
2869 if (presnap < (best - snap_threshold_s)) {
2874 start.set (best, 0);
2879 Editor::setup_toolbar ()
2881 HBox* mode_box = manage(new HBox);
2882 mode_box->set_border_width (2);
2883 mode_box->set_spacing(2);
2885 HBox* mouse_mode_box = manage (new HBox);
2886 HBox* mouse_mode_hbox = manage (new HBox);
2887 VBox* mouse_mode_vbox = manage (new VBox);
2888 Alignment* mouse_mode_align = manage (new Alignment);
2890 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2891 mouse_mode_size_group->add_widget (smart_mode_button);
2892 mouse_mode_size_group->add_widget (mouse_move_button);
2893 mouse_mode_size_group->add_widget (mouse_cut_button);
2894 mouse_mode_size_group->add_widget (mouse_select_button);
2895 mouse_mode_size_group->add_widget (mouse_timefx_button);
2896 mouse_mode_size_group->add_widget (mouse_audition_button);
2897 mouse_mode_size_group->add_widget (mouse_draw_button);
2898 mouse_mode_size_group->add_widget (mouse_content_button);
2900 if (!Profile->get_mixbus()) {
2901 mouse_mode_size_group->add_widget (zoom_in_button);
2902 mouse_mode_size_group->add_widget (zoom_out_button);
2903 mouse_mode_size_group->add_widget (zoom_out_full_button);
2904 mouse_mode_size_group->add_widget (zoom_focus_selector);
2905 mouse_mode_size_group->add_widget (tav_shrink_button);
2906 mouse_mode_size_group->add_widget (tav_expand_button);
2908 mouse_mode_size_group->add_widget (zoom_preset_selector);
2909 mouse_mode_size_group->add_widget (visible_tracks_selector);
2912 mouse_mode_size_group->add_widget (grid_type_selector);
2913 mouse_mode_size_group->add_widget (snap_mode_button);
2915 mouse_mode_size_group->add_widget (edit_point_selector);
2916 mouse_mode_size_group->add_widget (edit_mode_selector);
2918 mouse_mode_size_group->add_widget (*nudge_clock);
2919 mouse_mode_size_group->add_widget (nudge_forward_button);
2920 mouse_mode_size_group->add_widget (nudge_backward_button);
2922 mouse_mode_hbox->set_spacing (2);
2924 if (!ARDOUR::Profile->get_trx()) {
2925 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2928 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2929 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2931 if (!ARDOUR::Profile->get_mixbus()) {
2932 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2933 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2936 if (!ARDOUR::Profile->get_trx()) {
2937 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2938 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2939 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2942 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2944 mouse_mode_align->add (*mouse_mode_vbox);
2945 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2947 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2949 edit_mode_selector.set_name ("mouse mode button");
2951 if (!ARDOUR::Profile->get_trx()) {
2952 mode_box->pack_start (edit_mode_selector, false, false);
2953 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2954 mode_box->pack_start (edit_point_selector, false, false);
2955 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2958 mode_box->pack_start (*mouse_mode_box, false, false);
2962 _zoom_box.set_spacing (2);
2963 _zoom_box.set_border_width (2);
2967 zoom_preset_selector.set_name ("zoom button");
2968 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2970 zoom_in_button.set_name ("zoom button");
2971 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2972 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2973 zoom_in_button.set_related_action (act);
2975 zoom_out_button.set_name ("zoom button");
2976 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2977 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2978 zoom_out_button.set_related_action (act);
2980 zoom_out_full_button.set_name ("zoom button");
2981 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2982 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2983 zoom_out_full_button.set_related_action (act);
2985 zoom_focus_selector.set_name ("zoom button");
2987 if (ARDOUR::Profile->get_mixbus()) {
2988 _zoom_box.pack_start (zoom_preset_selector, false, false);
2989 } else if (ARDOUR::Profile->get_trx()) {
2990 mode_box->pack_start (zoom_out_button, false, false);
2991 mode_box->pack_start (zoom_in_button, false, false);
2993 _zoom_box.pack_start (zoom_out_button, false, false);
2994 _zoom_box.pack_start (zoom_in_button, false, false);
2995 _zoom_box.pack_start (zoom_out_full_button, false, false);
2996 _zoom_box.pack_start (zoom_focus_selector, false, false);
2999 /* Track zoom buttons */
3000 _track_box.set_spacing (2);
3001 _track_box.set_border_width (2);
3003 visible_tracks_selector.set_name ("zoom button");
3004 if (Profile->get_mixbus()) {
3005 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3007 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3010 tav_expand_button.set_name ("zoom button");
3011 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3012 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3013 tav_expand_button.set_related_action (act);
3015 tav_shrink_button.set_name ("zoom button");
3016 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3017 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3018 tav_shrink_button.set_related_action (act);
3020 if (ARDOUR::Profile->get_mixbus()) {
3021 _track_box.pack_start (visible_tracks_selector);
3022 } else if (ARDOUR::Profile->get_trx()) {
3023 _track_box.pack_start (tav_shrink_button);
3024 _track_box.pack_start (tav_expand_button);
3026 _track_box.pack_start (visible_tracks_selector);
3027 _track_box.pack_start (tav_shrink_button);
3028 _track_box.pack_start (tav_expand_button);
3031 snap_box.set_spacing (2);
3032 snap_box.set_border_width (2);
3034 grid_type_selector.set_name ("mouse mode button");
3036 snap_mode_button.set_name ("mouse mode button");
3038 edit_point_selector.set_name ("mouse mode button");
3040 snap_box.pack_start (snap_mode_button, false, false);
3041 snap_box.pack_start (grid_type_selector, false, false);
3045 HBox *nudge_box = manage (new HBox);
3046 nudge_box->set_spacing (2);
3047 nudge_box->set_border_width (2);
3049 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3050 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3052 nudge_box->pack_start (nudge_backward_button, false, false);
3053 nudge_box->pack_start (nudge_forward_button, false, false);
3054 nudge_box->pack_start (*nudge_clock, false, false);
3057 /* Pack everything in... */
3059 toolbar_hbox.set_spacing (2);
3060 toolbar_hbox.set_border_width (2);
3062 toolbar_hbox.pack_start (*mode_box, false, false);
3064 if (!ARDOUR::Profile->get_trx()) {
3066 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3068 toolbar_hbox.pack_start (snap_box, false, false);
3070 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3072 toolbar_hbox.pack_start (*nudge_box, false, false);
3074 //zoom tools on right ege
3076 toolbar_hbox.pack_end (_zoom_box, false, false);
3078 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3080 toolbar_hbox.pack_end (_track_box, false, false);
3084 toolbar_hbox.show_all ();
3088 Editor::build_edit_point_menu ()
3090 using namespace Menu_Helpers;
3092 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3093 if(!Profile->get_mixbus())
3094 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3095 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3097 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3101 Editor::build_edit_mode_menu ()
3103 using namespace Menu_Helpers;
3105 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3106 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3107 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3108 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3110 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3114 Editor::build_grid_type_menu ()
3116 using namespace Menu_Helpers;
3118 //main grid: bars, quarter-notes, etc
3119 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3120 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3121 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3122 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3123 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3124 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3125 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3126 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3129 grid_type_selector.AddMenuElem(SeparatorElem());
3130 Gtk::Menu *_triplet_menu = manage (new Menu);
3131 MenuList& triplet_items (_triplet_menu->items());
3133 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3) ));
3134 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6) ));
3135 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12) ));
3136 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24) ));
3138 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3141 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3142 MenuList& quintuplet_items (_quintuplet_menu->items());
3144 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5) ));
3145 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10) ));
3146 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20) ));
3148 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3151 Gtk::Menu *_septuplet_menu = manage (new Menu);
3152 MenuList& septuplet_items (_septuplet_menu->items());
3154 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7) ));
3155 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14) ));
3156 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28) ));
3158 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3160 grid_type_selector.AddMenuElem(SeparatorElem());
3161 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
3162 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3163 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
3165 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
3169 Editor::setup_tooltips ()
3171 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3172 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3173 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3174 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3175 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3176 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3177 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3178 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3179 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3180 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3181 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3182 set_tooltip (zoom_in_button, _("Zoom In"));
3183 set_tooltip (zoom_out_button, _("Zoom Out"));
3184 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3185 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3186 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3187 set_tooltip (tav_expand_button, _("Expand Tracks"));
3188 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3189 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3190 set_tooltip (grid_type_selector, _("Grid Mode"));
3191 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3192 set_tooltip (edit_point_selector, _("Edit Point"));
3193 set_tooltip (edit_mode_selector, _("Edit Mode"));
3194 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3198 Editor::convert_drop_to_paths (
3199 vector<string>& paths,
3200 const RefPtr<Gdk::DragContext>& /*context*/,
3203 const SelectionData& data,
3207 if (_session == 0) {
3211 vector<string> uris = data.get_uris();
3215 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3216 are actually URI lists. So do it by hand.
3219 if (data.get_target() != "text/plain") {
3223 /* Parse the "uri-list" format that Nautilus provides,
3224 where each pathname is delimited by \r\n.
3226 THERE MAY BE NO NULL TERMINATING CHAR!!!
3229 string txt = data.get_text();
3233 p = (char *) malloc (txt.length() + 1);
3234 txt.copy (p, txt.length(), 0);
3235 p[txt.length()] = '\0';
3241 while (g_ascii_isspace (*p))
3245 while (*q && (*q != '\n') && (*q != '\r')) {
3252 while (q > p && g_ascii_isspace (*q))
3257 uris.push_back (string (p, q - p + 1));
3261 p = strchr (p, '\n');
3273 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3274 if ((*i).substr (0,7) == "file://") {
3275 paths.push_back (Glib::filename_from_uri (*i));
3283 Editor::new_tempo_section ()
3288 Editor::map_transport_state ()
3290 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3292 if (_session && _session->transport_stopped()) {
3293 have_pending_keyboard_selection = false;
3296 update_loop_range_view ();
3300 Editor::transport_looped ()
3302 /* reset Playhead position interpolation.
3303 * see Editor::super_rapid_screen_update
3305 _last_update_time = 0;
3311 Editor::begin_selection_op_history ()
3313 selection_op_cmd_depth = 0;
3314 selection_op_history_it = 0;
3316 while(!selection_op_history.empty()) {
3317 delete selection_op_history.front();
3318 selection_op_history.pop_front();
3321 selection_undo_action->set_sensitive (false);
3322 selection_redo_action->set_sensitive (false);
3323 selection_op_history.push_front (&_selection_memento->get_state ());
3327 Editor::begin_reversible_selection_op (string name)
3330 //cerr << name << endl;
3331 /* begin/commit pairs can be nested */
3332 selection_op_cmd_depth++;
3337 Editor::commit_reversible_selection_op ()
3340 if (selection_op_cmd_depth == 1) {
3342 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3344 The user has undone some selection ops and then made a new one,
3345 making anything earlier in the list invalid.
3348 list<XMLNode *>::iterator it = selection_op_history.begin();
3349 list<XMLNode *>::iterator e_it = it;
3350 advance (e_it, selection_op_history_it);
3352 for ( ; it != e_it; ++it) {
3355 selection_op_history.erase (selection_op_history.begin(), e_it);
3358 selection_op_history.push_front (&_selection_memento->get_state ());
3359 selection_op_history_it = 0;
3361 selection_undo_action->set_sensitive (true);
3362 selection_redo_action->set_sensitive (false);
3365 if (selection_op_cmd_depth > 0) {
3366 selection_op_cmd_depth--;
3372 Editor::undo_selection_op ()
3375 selection_op_history_it++;
3377 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3378 if (n == selection_op_history_it) {
3379 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3380 selection_redo_action->set_sensitive (true);
3384 /* is there an earlier entry? */
3385 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3386 selection_undo_action->set_sensitive (false);
3392 Editor::redo_selection_op ()
3395 if (selection_op_history_it > 0) {
3396 selection_op_history_it--;
3399 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3400 if (n == selection_op_history_it) {
3401 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3402 selection_undo_action->set_sensitive (true);
3407 if (selection_op_history_it == 0) {
3408 selection_redo_action->set_sensitive (false);
3414 Editor::begin_reversible_command (string name)
3417 before.push_back (&_selection_memento->get_state ());
3418 _session->begin_reversible_command (name);
3423 Editor::begin_reversible_command (GQuark q)
3426 before.push_back (&_selection_memento->get_state ());
3427 _session->begin_reversible_command (q);
3432 Editor::abort_reversible_command ()
3435 while(!before.empty()) {
3436 delete before.front();
3439 _session->abort_reversible_command ();
3444 Editor::commit_reversible_command ()
3447 if (before.size() == 1) {
3448 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3449 redo_action->set_sensitive(false);
3450 undo_action->set_sensitive(true);
3451 begin_selection_op_history ();
3454 if (before.empty()) {
3455 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3460 _session->commit_reversible_command ();
3465 Editor::history_changed ()
3469 if (undo_action && _session) {
3470 if (_session->undo_depth() == 0) {
3471 label = S_("Command|Undo");
3473 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3475 undo_action->property_label() = label;
3478 if (redo_action && _session) {
3479 if (_session->redo_depth() == 0) {
3481 redo_action->set_sensitive (false);
3483 label = string_compose(_("Redo (%1)"), _session->next_redo());
3484 redo_action->set_sensitive (true);
3486 redo_action->property_label() = label;
3491 Editor::duplicate_range (bool with_dialog)
3495 RegionSelection rs = get_regions_from_selection_and_entered ();
3497 if ( selection->time.length() == 0 && rs.empty()) {
3503 ArdourDialog win (_("Duplicate"));
3504 Label label (_("Number of duplications:"));
3505 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3506 SpinButton spinner (adjustment, 0.0, 1);
3509 win.get_vbox()->set_spacing (12);
3510 win.get_vbox()->pack_start (hbox);
3511 hbox.set_border_width (6);
3512 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3514 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3515 place, visually. so do this by hand.
3518 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3519 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3520 spinner.grab_focus();
3526 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3527 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3528 win.set_default_response (RESPONSE_ACCEPT);
3530 spinner.grab_focus ();
3532 switch (win.run ()) {
3533 case RESPONSE_ACCEPT:
3539 times = adjustment.get_value();
3542 if ((current_mouse_mode() == MouseRange)) {
3543 if (selection->time.length()) {
3544 duplicate_selection (times);
3546 } else if (get_smart_mode()) {
3547 if (selection->time.length()) {
3548 duplicate_selection (times);
3550 duplicate_some_regions (rs, times);
3552 duplicate_some_regions (rs, times);
3557 Editor::set_edit_mode (EditMode m)
3559 Config->set_edit_mode (m);
3563 Editor::cycle_edit_mode ()
3565 switch (Config->get_edit_mode()) {
3567 Config->set_edit_mode (Ripple);
3571 Config->set_edit_mode (Lock);
3574 Config->set_edit_mode (Slide);
3580 Editor::edit_mode_selection_done ( EditMode m )
3582 Config->set_edit_mode ( m );
3586 Editor::grid_type_selection_done (GridType gridtype)
3588 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3590 ract->set_active ();
3595 Editor::snap_mode_selection_done (SnapMode mode)
3597 RefPtr<RadioAction> ract = snap_mode_action (mode);
3600 ract->set_active (true);
3605 Editor::cycle_edit_point (bool with_marker)
3607 if(Profile->get_mixbus())
3608 with_marker = false;
3610 switch (_edit_point) {
3612 set_edit_point_preference (EditAtPlayhead);
3614 case EditAtPlayhead:
3616 set_edit_point_preference (EditAtSelectedMarker);
3618 set_edit_point_preference (EditAtMouse);
3621 case EditAtSelectedMarker:
3622 set_edit_point_preference (EditAtMouse);
3628 Editor::edit_point_selection_done (EditPoint ep)
3630 set_edit_point_preference ( ep );
3634 Editor::build_zoom_focus_menu ()
3636 using namespace Menu_Helpers;
3638 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3639 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3640 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3641 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3642 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3643 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3645 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3649 Editor::zoom_focus_selection_done ( ZoomFocus f )
3651 RefPtr<RadioAction> ract = zoom_focus_action (f);
3653 ract->set_active ();
3658 Editor::build_track_count_menu ()
3660 using namespace Menu_Helpers;
3662 if (!Profile->get_mixbus()) {
3663 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3665 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3668 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3669 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3670 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3671 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3672 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3673 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3674 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3675 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3677 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3678 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3679 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3680 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3681 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3682 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3683 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3684 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3685 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3686 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3688 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3689 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3690 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3691 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3692 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3693 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3694 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3695 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3696 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3697 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3698 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3699 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3704 Editor::set_zoom_preset (int64_t ms)
3707 temporal_zoom_session();
3711 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3712 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3716 Editor::set_visible_track_count (int32_t n)
3718 _visible_track_count = n;
3720 /* if the canvas hasn't really been allocated any size yet, just
3721 record the desired number of visible tracks and return. when canvas
3722 allocation happens, we will get called again and then we can do the
3726 if (_visible_canvas_height <= 1) {
3732 DisplaySuspender ds;
3734 if (_visible_track_count > 0) {
3735 h = trackviews_height() / _visible_track_count;
3736 std::ostringstream s;
3737 s << _visible_track_count;
3739 } else if (_visible_track_count == 0) {
3741 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3742 if ((*i)->marked_for_display()) {
3744 TimeAxisView::Children cl ((*i)->get_child_list ());
3745 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3746 if ((*j)->marked_for_display()) {
3753 visible_tracks_selector.set_text (X_("*"));
3756 h = trackviews_height() / n;
3759 /* negative value means that the visible track count has
3760 been overridden by explicit track height changes.
3762 visible_tracks_selector.set_text (X_("*"));
3766 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3767 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3770 if (str != visible_tracks_selector.get_text()) {
3771 visible_tracks_selector.set_text (str);
3776 Editor::override_visible_track_count ()
3778 _visible_track_count = -1;
3779 visible_tracks_selector.set_text ( _("*") );
3783 Editor::edit_controls_button_release (GdkEventButton* ev)
3785 if (Keyboard::is_context_menu_event (ev)) {
3786 ARDOUR_UI::instance()->add_route ();
3787 } else if (ev->button == 1) {
3788 selection->clear_tracks ();
3795 Editor::mouse_select_button_release (GdkEventButton* ev)
3797 /* this handles just right-clicks */
3799 if (ev->button != 3) {
3807 Editor::set_zoom_focus (ZoomFocus f)
3809 string str = zoom_focus_strings[(int)f];
3811 if (str != zoom_focus_selector.get_text()) {
3812 zoom_focus_selector.set_text (str);
3815 if (zoom_focus != f) {
3822 Editor::cycle_zoom_focus ()
3824 switch (zoom_focus) {
3826 set_zoom_focus (ZoomFocusRight);
3828 case ZoomFocusRight:
3829 set_zoom_focus (ZoomFocusCenter);
3831 case ZoomFocusCenter:
3832 set_zoom_focus (ZoomFocusPlayhead);
3834 case ZoomFocusPlayhead:
3835 set_zoom_focus (ZoomFocusMouse);
3837 case ZoomFocusMouse:
3838 set_zoom_focus (ZoomFocusEdit);
3841 set_zoom_focus (ZoomFocusLeft);
3847 Editor::update_grid ()
3849 if ( grid_musical() ) {
3850 std::vector<TempoMap::BBTPoint> grid;
3851 if (bbt_ruler_scale != bbt_show_many) {
3852 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3854 maybe_draw_grid_lines ();
3855 } else if ( grid_nonmusical() ) {
3856 maybe_draw_grid_lines ();
3863 Editor::toggle_follow_playhead ()
3865 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3867 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3868 set_follow_playhead (tact->get_active());
3872 /** @param yn true to follow playhead, otherwise false.
3873 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3876 Editor::set_follow_playhead (bool yn, bool catch_up)
3878 if (_follow_playhead != yn) {
3879 if ((_follow_playhead = yn) == true && catch_up) {
3881 reset_x_origin_to_follow_playhead ();
3888 Editor::toggle_stationary_playhead ()
3890 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3892 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3893 set_stationary_playhead (tact->get_active());
3898 Editor::set_stationary_playhead (bool yn)
3900 if (_stationary_playhead != yn) {
3901 if ((_stationary_playhead = yn) == true) {
3903 // FIXME need a 3.0 equivalent of this 2.X call
3904 // update_current_screen ();
3911 Editor::playlist_selector () const
3913 return *_playlist_selector;
3917 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3919 if (paste_count == 0) {
3920 /* don't bother calculating an offset that will be zero anyway */
3924 /* calculate basic unsnapped multi-paste offset */
3925 samplecnt_t offset = paste_count * duration;
3927 /* snap offset so pos + offset is aligned to the grid */
3928 MusicSample offset_pos (pos + offset, 0);
3929 snap_to(offset_pos, RoundUpMaybe);
3930 offset = offset_pos.sample - pos;
3936 Editor::get_grid_beat_divisions(samplepos_t position)
3938 switch (_grid_type) {
3939 case GridTypeBeatDiv32: return 32;
3940 case GridTypeBeatDiv28: return 28;
3941 case GridTypeBeatDiv24: return 24;
3942 case GridTypeBeatDiv20: return 20;
3943 case GridTypeBeatDiv16: return 16;
3944 case GridTypeBeatDiv14: return 14;
3945 case GridTypeBeatDiv12: return 12;
3946 case GridTypeBeatDiv10: return 10;
3947 case GridTypeBeatDiv8: return 8;
3948 case GridTypeBeatDiv7: return 7;
3949 case GridTypeBeatDiv6: return 6;
3950 case GridTypeBeatDiv5: return 5;
3951 case GridTypeBeatDiv4: return 4;
3952 case GridTypeBeatDiv3: return 3;
3953 case GridTypeBeatDiv2: return 2;
3955 case GridTypeNone: return 0;
3956 case GridTypeSmpte: return 0;
3957 case GridTypeMinSec: return 0;
3958 case GridTypeSamples: return 0;
3964 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
3965 if the grid is non-musical, returns 0.
3966 if the grid is snapped to bars, returns -1.
3967 @param event_state the current keyboard modifier mask.
3970 Editor::get_grid_music_divisions (uint32_t event_state)
3972 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
3976 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
3980 switch (_grid_type) {
3981 case GridTypeBeatDiv32: return 32;
3982 case GridTypeBeatDiv28: return 28;
3983 case GridTypeBeatDiv24: return 24;
3984 case GridTypeBeatDiv20: return 20;
3985 case GridTypeBeatDiv16: return 16;
3986 case GridTypeBeatDiv14: return 14;
3987 case GridTypeBeatDiv12: return 12;
3988 case GridTypeBeatDiv10: return 10;
3989 case GridTypeBeatDiv8: return 8;
3990 case GridTypeBeatDiv7: return 7;
3991 case GridTypeBeatDiv6: return 6;
3992 case GridTypeBeatDiv5: return 5;
3993 case GridTypeBeatDiv4: return 4;
3994 case GridTypeBeatDiv3: return 3;
3995 case GridTypeBeatDiv2: return 2;
3996 case GridTypeBeat: return 1;
3997 case GridTypeBar : return -1;
3999 case GridTypeNone: return 0;
4000 case GridTypeSmpte: return 0;
4001 case GridTypeMinSec: return 0;
4002 case GridTypeSamples: return 0;
4008 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4012 const unsigned divisions = get_grid_beat_divisions(position);
4014 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4017 switch (_grid_type) {
4019 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4022 const Meter& m = _session->tempo_map().meter_at_sample (position);
4023 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4031 return Temporal::Beats();
4035 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4039 ret = nudge_clock->current_duration (pos);
4040 next = ret + 1; /* XXXX fix me */
4046 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4048 ArdourDialog dialog (_("Playlist Deletion"));
4049 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4050 "If it is kept, its audio files will not be cleaned.\n"
4051 "If it is deleted, audio files used by it alone will be cleaned."),
4054 dialog.set_position (WIN_POS_CENTER);
4055 dialog.get_vbox()->pack_start (label);
4059 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4060 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4061 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4062 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4063 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4065 // by default gtk uses the left most button
4066 keep->grab_focus ();
4068 switch (dialog.run ()) {
4070 /* keep this and all remaining ones */
4075 /* delete this and all others */
4079 case RESPONSE_ACCEPT:
4080 /* delete the playlist */
4084 case RESPONSE_REJECT:
4085 /* keep the playlist */
4097 Editor::audio_region_selection_covers (samplepos_t where)
4099 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4100 if ((*a)->region()->covers (where)) {
4109 Editor::prepare_for_cleanup ()
4111 cut_buffer->clear_regions ();
4112 cut_buffer->clear_playlists ();
4114 selection->clear_regions ();
4115 selection->clear_playlists ();
4117 _regions->suspend_redisplay ();
4121 Editor::finish_cleanup ()
4123 _regions->resume_redisplay ();
4127 Editor::transport_loop_location()
4130 return _session->locations()->auto_loop_location();
4137 Editor::transport_punch_location()
4140 return _session->locations()->auto_punch_location();
4147 Editor::control_layout_scroll (GdkEventScroll* ev)
4149 /* Just forward to the normal canvas scroll method. The coordinate
4150 systems are different but since the canvas is always larger than the
4151 track headers, and aligned with the trackview area, this will work.
4153 In the not too distant future this layout is going away anyway and
4154 headers will be on the canvas.
4156 return canvas_scroll_event (ev, false);
4160 Editor::session_state_saved (string)
4163 _snapshots->redisplay ();
4167 Editor::maximise_editing_space ()
4173 Gtk::Window* toplevel = current_toplevel();
4176 toplevel->fullscreen ();
4182 Editor::restore_editing_space ()
4188 Gtk::Window* toplevel = current_toplevel();
4191 toplevel->unfullscreen();
4197 * Make new playlists for a given track and also any others that belong
4198 * to the same active route group with the `select' property.
4203 Editor::new_playlists (TimeAxisView* v)
4205 begin_reversible_command (_("new playlists"));
4206 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4207 _session->playlists->get (playlists);
4208 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4209 commit_reversible_command ();
4213 * Use a copy of the current playlist for a given track and also any others that belong
4214 * to the same active route group with the `select' property.
4219 Editor::copy_playlists (TimeAxisView* v)
4221 begin_reversible_command (_("copy playlists"));
4222 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4223 _session->playlists->get (playlists);
4224 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4225 commit_reversible_command ();
4228 /** Clear the current playlist for a given track and also any others that belong
4229 * to the same active route group with the `select' property.
4234 Editor::clear_playlists (TimeAxisView* v)
4236 begin_reversible_command (_("clear playlists"));
4237 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4238 _session->playlists->get (playlists);
4239 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4240 commit_reversible_command ();
4244 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4246 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4250 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4252 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4256 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4258 atv.clear_playlist ();
4262 Editor::get_y_origin () const
4264 return vertical_adjustment.get_value ();
4267 /** Queue up a change to the viewport x origin.
4268 * @param sample New x origin.
4271 Editor::reset_x_origin (samplepos_t sample)
4273 pending_visual_change.add (VisualChange::TimeOrigin);
4274 pending_visual_change.time_origin = sample;
4275 ensure_visual_change_idle_handler ();
4279 Editor::reset_y_origin (double y)
4281 pending_visual_change.add (VisualChange::YOrigin);
4282 pending_visual_change.y_origin = y;
4283 ensure_visual_change_idle_handler ();
4287 Editor::reset_zoom (samplecnt_t spp)
4289 if (spp == samples_per_pixel) {
4293 pending_visual_change.add (VisualChange::ZoomLevel);
4294 pending_visual_change.samples_per_pixel = spp;
4295 ensure_visual_change_idle_handler ();
4299 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4301 reset_x_origin (sample);
4304 if (!no_save_visual) {
4305 undo_visual_stack.push_back (current_visual_state(false));
4309 Editor::VisualState::VisualState (bool with_tracks)
4310 : gui_state (with_tracks ? new GUIObjectState : 0)
4314 Editor::VisualState::~VisualState ()
4319 Editor::VisualState*
4320 Editor::current_visual_state (bool with_tracks)
4322 VisualState* vs = new VisualState (with_tracks);
4323 vs->y_position = vertical_adjustment.get_value();
4324 vs->samples_per_pixel = samples_per_pixel;
4325 vs->_leftmost_sample = _leftmost_sample;
4326 vs->zoom_focus = zoom_focus;
4329 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4336 Editor::undo_visual_state ()
4338 if (undo_visual_stack.empty()) {
4342 VisualState* vs = undo_visual_stack.back();
4343 undo_visual_stack.pop_back();
4346 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4349 use_visual_state (*vs);
4354 Editor::redo_visual_state ()
4356 if (redo_visual_stack.empty()) {
4360 VisualState* vs = redo_visual_stack.back();
4361 redo_visual_stack.pop_back();
4363 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4364 // why do we check here?
4365 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4368 use_visual_state (*vs);
4373 Editor::swap_visual_state ()
4375 if (undo_visual_stack.empty()) {
4376 redo_visual_state ();
4378 undo_visual_state ();
4383 Editor::use_visual_state (VisualState& vs)
4385 PBD::Unwinder<bool> nsv (no_save_visual, true);
4386 DisplaySuspender ds;
4388 vertical_adjustment.set_value (vs.y_position);
4390 set_zoom_focus (vs.zoom_focus);
4391 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4394 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4396 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4397 (*i)->clear_property_cache();
4398 (*i)->reset_visual_state ();
4402 _routes->update_visibility ();
4405 /** This is the core function that controls the zoom level of the canvas. It is called
4406 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4407 * @param spp new number of samples per pixel
4410 Editor::set_samples_per_pixel (samplecnt_t spp)
4416 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4417 const samplecnt_t lots_of_pixels = 4000;
4419 /* if the zoom level is greater than what you'd get trying to display 3
4420 * days of audio on a really big screen, then it's too big.
4423 if (spp * lots_of_pixels > three_days) {
4427 samples_per_pixel = spp;
4431 Editor::on_samples_per_pixel_changed ()
4433 bool const showing_time_selection = selection->time.length() > 0;
4435 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4436 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4437 (*i)->reshow_selection (selection->time);
4441 ZoomChanged (); /* EMIT_SIGNAL */
4443 ArdourCanvas::GtkCanvasViewport* c;
4445 c = get_track_canvas();
4447 c->canvas()->zoomed ();
4450 if (playhead_cursor) {
4451 playhead_cursor->set_position (playhead_cursor->current_sample ());
4454 refresh_location_display();
4455 _summary->set_overlays_dirty ();
4457 update_marker_labels ();
4463 Editor::playhead_cursor_sample () const
4465 return playhead_cursor->current_sample();
4469 Editor::queue_visual_videotimeline_update ()
4471 pending_visual_change.add (VisualChange::VideoTimeline);
4472 ensure_visual_change_idle_handler ();
4476 Editor::ensure_visual_change_idle_handler ()
4478 if (pending_visual_change.idle_handler_id < 0) {
4479 // see comment in add_to_idle_resize above.
4480 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4481 pending_visual_change.being_handled = false;
4486 Editor::_idle_visual_changer (void* arg)
4488 return static_cast<Editor*>(arg)->idle_visual_changer ();
4492 Editor::pre_render ()
4494 visual_change_queued = false;
4496 if (pending_visual_change.pending != 0) {
4497 ensure_visual_change_idle_handler();
4502 Editor::idle_visual_changer ()
4504 pending_visual_change.idle_handler_id = -1;
4506 if (pending_visual_change.pending == 0) {
4510 /* set_horizontal_position() below (and maybe other calls) call
4511 gtk_main_iteration(), so it's possible that a signal will be handled
4512 half-way through this method. If this signal wants an
4513 idle_visual_changer we must schedule another one after this one, so
4514 mark the idle_handler_id as -1 here to allow that. Also make a note
4515 that we are doing the visual change, so that changes in response to
4516 super-rapid-screen-update can be dropped if we are still processing
4520 if (visual_change_queued) {
4524 pending_visual_change.being_handled = true;
4526 VisualChange vc = pending_visual_change;
4528 pending_visual_change.pending = (VisualChange::Type) 0;
4530 visual_changer (vc);
4532 pending_visual_change.being_handled = false;
4534 visual_change_queued = true;
4536 return 0; /* this is always a one-shot call */
4540 Editor::visual_changer (const VisualChange& vc)
4543 * Changed first so the correct horizontal canvas position is calculated in
4544 * Editor::set_horizontal_position
4546 if (vc.pending & VisualChange::ZoomLevel) {
4547 set_samples_per_pixel (vc.samples_per_pixel);
4550 if (vc.pending & VisualChange::TimeOrigin) {
4551 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4552 set_horizontal_position (new_time_origin);
4555 if (vc.pending & VisualChange::YOrigin) {
4556 vertical_adjustment.set_value (vc.y_origin);
4560 * Now the canvas is in the final state before render the canvas items that
4561 * support the Item::prepare_for_render interface can calculate the correct
4562 * item to visible canvas intersection.
4564 if (vc.pending & VisualChange::ZoomLevel) {
4565 on_samples_per_pixel_changed ();
4567 compute_fixed_ruler_scale ();
4569 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4570 update_tempo_based_rulers ();
4573 if (!(vc.pending & VisualChange::ZoomLevel)) {
4575 * If the canvas is not being zoomed then the canvas items will not change
4576 * and cause Item::prepare_for_render to be called so do it here manually.
4578 * Not ideal, but I can't think of a better solution atm.
4580 _track_canvas->prepare_for_render();
4583 // If we are only scrolling vertically there is no need to update these
4584 if (vc.pending != VisualChange::YOrigin) {
4585 update_fixed_rulers ();
4586 redisplay_grid (true);
4588 /* video frames & position need to be updated for zoom, horiz-scroll
4589 * and (explicitly) VisualChange::VideoTimeline.
4591 update_video_timeline();
4594 _summary->set_overlays_dirty ();
4597 struct EditorOrderTimeAxisSorter {
4598 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4599 return a->order () < b->order ();
4604 Editor::sort_track_selection (TrackViewList& sel)
4606 EditorOrderTimeAxisSorter cmp;
4611 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4614 samplepos_t where = 0;
4615 EditPoint ep = _edit_point;
4617 if (Profile->get_mixbus()) {
4618 if (ep == EditAtSelectedMarker) {
4619 ep = EditAtPlayhead;
4623 if (from_outside_canvas && (ep == EditAtMouse)) {
4624 ep = EditAtPlayhead;
4625 } else if (from_context_menu && (ep == EditAtMouse)) {
4626 return canvas_event_sample (&context_click_event, 0, 0);
4629 if (entered_marker) {
4630 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4631 return entered_marker->position();
4634 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4635 ep = EditAtSelectedMarker;
4638 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4639 ep = EditAtPlayhead;
4642 MusicSample snap_mf (0, 0);
4645 case EditAtPlayhead:
4646 if (_dragging_playhead && _control_scroll_target) {
4647 where = *_control_scroll_target;
4649 where = _session->audible_sample();
4651 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4654 case EditAtSelectedMarker:
4655 if (!selection->markers.empty()) {
4657 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4660 where = loc->start();
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4672 if (!mouse_sample (where, ignored)) {
4673 /* XXX not right but what can we do ? */
4676 snap_mf.sample = where;
4678 where = snap_mf.sample;
4679 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4687 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4689 if (!_session) return;
4691 begin_reversible_command (cmd);
4695 if ((tll = transport_loop_location()) == 0) {
4696 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4697 XMLNode &before = _session->locations()->get_state();
4698 _session->locations()->add (loc, true);
4699 _session->set_auto_loop_location (loc);
4700 XMLNode &after = _session->locations()->get_state();
4701 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4703 XMLNode &before = tll->get_state();
4704 tll->set_hidden (false, this);
4705 tll->set (start, end);
4706 XMLNode &after = tll->get_state();
4707 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4710 commit_reversible_command ();
4714 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4716 if (!_session) return;
4718 begin_reversible_command (cmd);
4722 if ((tpl = transport_punch_location()) == 0) {
4723 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4724 XMLNode &before = _session->locations()->get_state();
4725 _session->locations()->add (loc, true);
4726 _session->set_auto_punch_location (loc);
4727 XMLNode &after = _session->locations()->get_state();
4728 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4730 XMLNode &before = tpl->get_state();
4731 tpl->set_hidden (false, this);
4732 tpl->set (start, end);
4733 XMLNode &after = tpl->get_state();
4734 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4737 commit_reversible_command ();
4740 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4741 * @param rs List to which found regions are added.
4742 * @param where Time to look at.
4743 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4746 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4748 const TrackViewList* tracks;
4751 tracks = &track_views;
4756 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4758 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4761 boost::shared_ptr<Track> tr;
4762 boost::shared_ptr<Playlist> pl;
4764 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4766 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4768 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4769 RegionView* rv = rtv->view()->find_view (*i);
4780 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4782 const TrackViewList* tracks;
4785 tracks = &track_views;
4790 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4791 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4793 boost::shared_ptr<Track> tr;
4794 boost::shared_ptr<Playlist> pl;
4796 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4798 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4800 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4802 RegionView* rv = rtv->view()->find_view (*i);
4813 /** Get regions using the following method:
4815 * Make a region list using:
4816 * (a) any selected regions
4817 * (b) the intersection of any selected tracks and the edit point(*)
4818 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4820 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4822 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4826 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4828 RegionSelection regions;
4830 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4831 regions.add (entered_regionview);
4833 regions = selection->regions;
4836 if ( regions.empty() ) {
4837 TrackViewList tracks = selection->tracks;
4839 if (!tracks.empty()) {
4840 /* no region selected or entered, but some selected tracks:
4841 * act on all regions on the selected tracks at the edit point
4843 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4844 get_regions_at(regions, where, tracks);
4851 /** Get regions using the following method:
4853 * Make a region list using:
4854 * (a) any selected regions
4855 * (b) the intersection of any selected tracks and the edit point(*)
4856 * (c) if neither exists, then whatever region is under the mouse
4858 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4860 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4863 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4865 RegionSelection regions;
4867 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4868 regions.add (entered_regionview);
4870 regions = selection->regions;
4873 if ( regions.empty() ) {
4874 TrackViewList tracks = selection->tracks;
4876 if (!tracks.empty()) {
4877 /* no region selected or entered, but some selected tracks:
4878 * act on all regions on the selected tracks at the edit point
4880 get_regions_at(regions, pos, tracks);
4887 /** Start with regions that are selected, or the entered regionview if none are selected.
4888 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4889 * of the regions that we started with.
4893 Editor::get_regions_from_selection_and_entered () const
4895 RegionSelection regions = selection->regions;
4897 if (regions.empty() && entered_regionview) {
4898 regions.add (entered_regionview);
4905 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4907 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4908 RouteTimeAxisView* rtav;
4910 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4911 boost::shared_ptr<Playlist> pl;
4912 std::vector<boost::shared_ptr<Region> > results;
4913 boost::shared_ptr<Track> tr;
4915 if ((tr = rtav->track()) == 0) {
4920 if ((pl = (tr->playlist())) != 0) {
4921 boost::shared_ptr<Region> r = pl->region_by_id (id);
4923 RegionView* rv = rtav->view()->find_view (r);
4925 regions.push_back (rv);
4934 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4937 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4938 MidiTimeAxisView* mtav;
4940 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4942 mtav->get_per_region_note_selection (selection);
4949 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4951 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4953 RouteTimeAxisView* tatv;
4955 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4957 boost::shared_ptr<Playlist> pl;
4958 vector<boost::shared_ptr<Region> > results;
4960 boost::shared_ptr<Track> tr;
4962 if ((tr = tatv->track()) == 0) {
4967 if ((pl = (tr->playlist())) != 0) {
4968 if (src_comparison) {
4969 pl->get_source_equivalent_regions (region, results);
4971 pl->get_region_list_equivalent_regions (region, results);
4975 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4976 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4977 regions.push_back (marv);
4986 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
4988 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4989 RouteTimeAxisView* tatv;
4990 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4991 if (!tatv->track()) {
4994 RegionView* marv = tatv->view()->find_view (region);
5004 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5006 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5007 RouteTimeAxisView* rtav;
5008 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5009 if (rtav->route() == route) {
5018 Editor::show_rhythm_ferret ()
5020 if (rhythm_ferret == 0) {
5021 rhythm_ferret = new RhythmFerret(*this);
5024 rhythm_ferret->set_session (_session);
5025 rhythm_ferret->show ();
5026 rhythm_ferret->present ();
5030 Editor::first_idle ()
5032 MessageDialog* dialog = 0;
5034 if (track_views.size() > 1) {
5035 Timers::TimerSuspender t;
5036 dialog = new MessageDialog (
5037 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5041 ARDOUR_UI::instance()->flush_pending (60);
5044 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5048 /* now that all regionviews should exist, setup region selection */
5052 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5053 /* this is cumulative: rs is NOT cleared each time */
5054 get_regionviews_by_id (*pr, rs);
5057 selection->set (rs);
5059 // first idle adds route children (automation tracks), so we need to redisplay here
5060 _routes->redisplay ();
5064 if (_session->undo_depth() == 0) {
5065 undo_action->set_sensitive(false);
5067 redo_action->set_sensitive(false);
5068 begin_selection_op_history ();
5074 Editor::_idle_resize (gpointer arg)
5076 return ((Editor*)arg)->idle_resize ();
5080 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5082 if (resize_idle_id < 0) {
5083 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5084 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5085 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5087 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5088 _pending_resize_amount = 0;
5091 /* make a note of the smallest resulting height, so that we can clamp the
5092 lower limit at TimeAxisView::hSmall */
5094 int32_t min_resulting = INT32_MAX;
5096 _pending_resize_amount += h;
5097 _pending_resize_view = view;
5099 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5101 if (selection->tracks.contains (_pending_resize_view)) {
5102 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5103 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5107 if (min_resulting < 0) {
5112 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5113 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5117 /** Handle pending resizing of tracks */
5119 Editor::idle_resize ()
5121 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5123 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5124 selection->tracks.contains (_pending_resize_view)) {
5126 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5127 if (*i != _pending_resize_view) {
5128 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5133 _pending_resize_amount = 0;
5134 _group_tabs->set_dirty ();
5135 resize_idle_id = -1;
5143 ENSURE_GUI_THREAD (*this, &Editor::located);
5146 playhead_cursor->set_position (_session->audible_sample ());
5147 if (_follow_playhead && !_pending_initial_locate) {
5148 reset_x_origin_to_follow_playhead ();
5152 _pending_locate_request = false;
5153 _pending_initial_locate = false;
5154 _last_update_time = 0;
5158 Editor::region_view_added (RegionView * rv)
5160 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5162 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5163 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5164 if (rv->region()->id () == (*rnote).first) {
5165 mrv->select_notes ((*rnote).second);
5166 selection->pending_midi_note_selection.erase(rnote);
5172 _summary->set_background_dirty ();
5174 mark_region_boundary_cache_dirty ();
5178 Editor::region_view_removed ()
5180 _summary->set_background_dirty ();
5182 mark_region_boundary_cache_dirty ();
5186 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5188 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5189 if ((*j)->stripable() == s) {
5198 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5200 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5201 if ((*j)->control() == c) {
5205 TimeAxisView::Children kids = (*j)->get_child_list ();
5207 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5208 if ((*k)->control() == c) {
5218 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5222 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5223 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5233 Editor::suspend_route_redisplay ()
5236 _routes->suspend_redisplay();
5241 Editor::resume_route_redisplay ()
5244 _routes->redisplay(); // queue redisplay
5245 _routes->resume_redisplay();
5250 Editor::add_vcas (VCAList& vlist)
5254 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5255 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5258 add_stripables (sl);
5262 Editor::add_routes (RouteList& rlist)
5266 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5270 add_stripables (sl);
5274 Editor::add_stripables (StripableList& sl)
5276 list<TimeAxisView*> new_views;
5277 boost::shared_ptr<VCA> v;
5278 boost::shared_ptr<Route> r;
5279 TrackViewList new_selection;
5280 bool from_scratch = (track_views.size() == 0);
5282 sl.sort (Stripable::Sorter());
5284 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5286 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5288 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5290 new_views.push_back (vtv);
5292 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5294 if (r->is_auditioner() || r->is_monitor()) {
5298 RouteTimeAxisView* rtv;
5299 DataType dt = r->input()->default_type();
5301 if (dt == ARDOUR::DataType::AUDIO) {
5302 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5304 } else if (dt == ARDOUR::DataType::MIDI) {
5305 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5308 throw unknown_type();
5311 new_views.push_back (rtv);
5312 track_views.push_back (rtv);
5313 new_selection.push_back (rtv);
5315 rtv->effective_gain_display ();
5317 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5318 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5322 if (new_views.size() > 0) {
5323 _routes->time_axis_views_added (new_views);
5324 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5327 /* note: !new_selection.empty() means that we got some routes rather
5331 if (!from_scratch && !new_selection.empty()) {
5332 selection->set (new_selection);
5333 begin_selection_op_history();
5336 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5337 show_editor_mixer (true);
5340 editor_list_button.set_sensitive (true);
5344 Editor::timeaxisview_deleted (TimeAxisView *tv)
5346 if (tv == entered_track) {
5350 if (_session && _session->deletion_in_progress()) {
5351 /* the situation is under control */
5355 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5357 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5359 _routes->route_removed (tv);
5361 TimeAxisView::Children c = tv->get_child_list ();
5362 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5363 if (entered_track == i->get()) {
5368 /* remove it from the list of track views */
5370 TrackViewList::iterator i;
5372 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5373 i = track_views.erase (i);
5376 /* update whatever the current mixer strip is displaying, if revelant */
5378 boost::shared_ptr<Route> route;
5381 route = rtav->route ();
5384 if (current_mixer_strip && current_mixer_strip->route() == route) {
5386 TimeAxisView* next_tv;
5388 if (track_views.empty()) {
5390 } else if (i == track_views.end()) {
5391 next_tv = track_views.front();
5396 // skip VCAs (cannot be selected, n/a in editor-mixer)
5397 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5398 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5399 next_tv = track_views.front();
5401 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5402 /* just in case: no master, only a VCA remains */
5408 set_selected_mixer_strip (*next_tv);
5410 /* make the editor mixer strip go away setting the
5411 * button to inactive (which also unticks the menu option)
5414 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5420 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5426 DisplaySuspender ds;
5427 PresentationInfo::ChangeSuspender cs;
5429 if (apply_to_selection) {
5430 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5432 TrackSelection::iterator j = i;
5435 hide_track_in_display (*i, false);
5440 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5442 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5443 // this will hide the mixer strip
5444 set_selected_mixer_strip (*tv);
5447 _routes->hide_track_in_display (*tv);
5452 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5457 _routes->show_track_in_display (*tv);
5458 if (move_into_view) {
5459 ensure_time_axis_view_is_visible (*tv, false);
5464 Editor::sync_track_view_list_and_routes ()
5466 track_views = TrackViewList (_routes->views ());
5468 _summary->set_background_dirty();
5469 _group_tabs->set_dirty ();
5471 return false; // do not call again (until needed)
5475 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5477 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5482 /** Find a StripableTimeAxisView by the ID of its stripable */
5483 StripableTimeAxisView*
5484 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5486 StripableTimeAxisView* v;
5488 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5489 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5490 if(v->stripable()->id() == id) {
5500 Editor::fit_route_group (RouteGroup *g)
5502 TrackViewList ts = axis_views_from_routes (g->route_list ());
5507 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5509 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5512 _session->cancel_audition ();
5516 if (_session->is_auditioning()) {
5517 _session->cancel_audition ();
5518 if (r == last_audition_region) {
5523 _session->audition_region (r);
5524 last_audition_region = r;
5529 Editor::hide_a_region (boost::shared_ptr<Region> r)
5531 r->set_hidden (true);
5535 Editor::show_a_region (boost::shared_ptr<Region> r)
5537 r->set_hidden (false);
5541 Editor::audition_region_from_region_list ()
5543 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5547 Editor::hide_region_from_region_list ()
5549 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5553 Editor::show_region_in_region_list ()
5555 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5559 Editor::step_edit_status_change (bool yn)
5562 start_step_editing ();
5564 stop_step_editing ();
5569 Editor::start_step_editing ()
5571 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5575 Editor::stop_step_editing ()
5577 step_edit_connection.disconnect ();
5581 Editor::check_step_edit ()
5583 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5584 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5586 mtv->check_step_edit ();
5590 return true; // do it again, till we stop
5594 Editor::scroll_press (Direction dir)
5596 ++_scroll_callbacks;
5598 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5599 /* delay the first auto-repeat */
5605 scroll_backward (1);
5613 scroll_up_one_track ();
5617 scroll_down_one_track ();
5621 /* do hacky auto-repeat */
5622 if (!_scroll_connection.connected ()) {
5624 _scroll_connection = Glib::signal_timeout().connect (
5625 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5628 _scroll_callbacks = 0;
5635 Editor::scroll_release ()
5637 _scroll_connection.disconnect ();
5640 /** Queue a change for the Editor viewport x origin to follow the playhead */
5642 Editor::reset_x_origin_to_follow_playhead ()
5644 samplepos_t const sample = playhead_cursor->current_sample ();
5646 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5648 if (_session->transport_speed() < 0) {
5650 if (sample > (current_page_samples() / 2)) {
5651 center_screen (sample-(current_page_samples()/2));
5653 center_screen (current_page_samples()/2);
5660 if (sample < _leftmost_sample) {
5662 if (_session->transport_rolling()) {
5663 /* rolling; end up with the playhead at the right of the page */
5664 l = sample - current_page_samples ();
5666 /* not rolling: end up with the playhead 1/4 of the way along the page */
5667 l = sample - current_page_samples() / 4;
5671 if (_session->transport_rolling()) {
5672 /* rolling: end up with the playhead on the left of the page */
5675 /* not rolling: end up with the playhead 3/4 of the way along the page */
5676 l = sample - 3 * current_page_samples() / 4;
5684 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5690 Editor::super_rapid_screen_update ()
5692 if (!_session || !_session->engine().running()) {
5696 /* METERING / MIXER STRIPS */
5698 /* update track meters, if required */
5699 if (contents().is_mapped() && meters_running) {
5700 RouteTimeAxisView* rtv;
5701 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5702 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5703 rtv->fast_update ();
5708 /* and any current mixer strip */
5709 if (current_mixer_strip) {
5710 current_mixer_strip->fast_update ();
5713 bool latent_locate = false;
5714 samplepos_t sample = _session->audible_sample (&latent_locate);
5715 const int64_t now = g_get_monotonic_time ();
5718 if (_session->exporting ()) {
5719 /* freewheel/export may be faster or slower than transport_speed() / SR.
5720 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5722 _last_update_time = 0;
5725 if (_last_update_time > 0) {
5726 /* interpolate and smoothen playhead position */
5727 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5728 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5729 err = sample - guess;
5731 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5732 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5735 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5737 err, _err_screen_engine);
5742 _err_screen_engine = 0;
5745 if (err > 8192 || latent_locate) {
5746 // in case of x-runs or freewheeling
5747 _last_update_time = 0;
5748 sample = _session->audible_sample ();
5750 _last_update_time = now;
5753 //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
5755 MusicSample where (sample, 0);
5756 if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
5757 snapped_cursor->hide ();
5758 } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
5759 snap_to (where); // can't use snap_to_with_modifier?
5760 snapped_cursor->set_position (where.sample);
5761 snapped_cursor->show ();
5762 } else if ( _edit_point == EditAtSelectedMarker ) {
5763 //NOTE: I don't think EditAtSelectedMarker should snap. they are what they are.
5764 //however, the current editing code -does- snap so I'll draw it that way for now.
5765 if ( !selection->markers.empty() ) {
5766 MusicSample ms (selection->markers.front()->position(), 0);
5767 snap_to (ms); // should use snap_to_with_modifier?
5768 snapped_cursor->set_position ( ms.sample );
5769 snapped_cursor->show ();
5771 } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it.
5772 snapped_cursor->show ();
5773 } else { //mouse is out of the editing canvas. hide the snapped_cursor
5774 snapped_cursor->hide ();
5777 /* There are a few reasons why we might not update the playhead / viewport stuff:
5779 * 1. we don't update things when there's a pending locate request, otherwise
5780 * when the editor requests a locate there is a chance that this method
5781 * will move the playhead before the locate request is processed, causing
5783 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5784 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5786 if (_pending_locate_request) {
5787 _last_update_time = 0;
5791 if (_dragging_playhead) {
5792 _last_update_time = 0;
5796 if (playhead_cursor->current_sample () == sample) {
5800 playhead_cursor->set_position (sample);
5802 if (_session->requested_return_sample() >= 0) {
5803 _last_update_time = 0;
5807 if (!_follow_playhead || pending_visual_change.being_handled) {
5808 /* We only do this if we aren't already
5809 * handling a visual change (ie if
5810 * pending_visual_change.being_handled is
5811 * false) so that these requests don't stack
5812 * up there are too many of them to handle in
5818 if (!_stationary_playhead) {
5819 reset_x_origin_to_follow_playhead ();
5821 samplepos_t const sample = playhead_cursor->current_sample ();
5822 double target = ((double)sample - (double)current_page_samples() / 2.0);
5823 if (target <= 0.0) {
5826 // compare to EditorCursor::set_position()
5827 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5828 double const new_pos = sample_to_pixel_unrounded (target);
5829 if (rint (new_pos) != rint (old_pos)) {
5830 reset_x_origin (pixel_to_sample (new_pos));
5837 Editor::session_going_away ()
5839 _have_idled = false;
5841 _session_connections.drop_connections ();
5843 super_rapid_screen_update_connection.disconnect ();
5845 selection->clear ();
5846 cut_buffer->clear ();
5848 clicked_regionview = 0;
5849 clicked_axisview = 0;
5850 clicked_routeview = 0;
5851 entered_regionview = 0;
5853 _last_update_time = 0;
5856 playhead_cursor->hide ();
5858 /* rip everything out of the list displays */
5862 _route_groups->clear ();
5864 /* do this first so that deleting a track doesn't reset cms to null
5865 and thus cause a leak.
5868 if (current_mixer_strip) {
5869 if (current_mixer_strip->get_parent() != 0) {
5870 global_hpacker.remove (*current_mixer_strip);
5872 delete current_mixer_strip;
5873 current_mixer_strip = 0;
5876 /* delete all trackviews */
5878 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5881 track_views.clear ();
5883 nudge_clock->set_session (0);
5885 editor_list_button.set_active(false);
5886 editor_list_button.set_sensitive(false);
5888 /* clear tempo/meter rulers */
5889 remove_metric_marks ();
5890 clear_marker_display ();
5896 stop_step_editing ();
5900 /* get rid of any existing editor mixer strip */
5902 WindowTitle title(Glib::get_application_name());
5903 title += _("Editor");
5905 own_window()->set_title (title.get_string());
5908 SessionHandlePtr::session_going_away ();
5912 Editor::trigger_script (int i)
5914 LuaInstance::instance()-> call_action (i);
5918 Editor::show_editor_list (bool yn)
5921 _editor_list_vbox.show ();
5923 _editor_list_vbox.hide ();
5928 Editor::change_region_layering_order (bool from_context_menu)
5930 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5932 if (!clicked_routeview) {
5933 if (layering_order_editor) {
5934 layering_order_editor->hide ();
5939 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5945 boost::shared_ptr<Playlist> pl = track->playlist();
5951 if (layering_order_editor == 0) {
5952 layering_order_editor = new RegionLayeringOrderEditor (*this);
5955 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5956 layering_order_editor->maybe_present ();
5960 Editor::update_region_layering_order_editor ()
5962 if (layering_order_editor && layering_order_editor->is_visible ()) {
5963 change_region_layering_order (true);
5968 Editor::setup_fade_images ()
5970 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5971 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5972 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5973 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5974 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5976 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5977 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5978 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5979 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5980 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5984 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5986 Editor::action_menu_item (std::string const & name)
5988 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5991 return *manage (a->create_menu_item ());
5995 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5997 EventBox* b = manage (new EventBox);
5998 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5999 Label* l = manage (new Label (name));
6003 _the_notebook.append_page (widget, *b);
6007 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6009 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6010 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6013 if (ev->type == GDK_2BUTTON_PRESS) {
6015 /* double-click on a notebook tab shrinks or expands the notebook */
6017 if (_notebook_shrunk) {
6018 if (pre_notebook_shrink_pane_width) {
6019 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6021 _notebook_shrunk = false;
6023 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6025 /* this expands the LHS of the edit pane to cover the notebook
6026 PAGE but leaves the tabs visible.
6028 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6029 _notebook_shrunk = true;
6037 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6039 using namespace Menu_Helpers;
6041 MenuList& items = _control_point_context_menu.items ();
6044 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6045 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6046 if (!can_remove_control_point (item)) {
6047 items.back().set_sensitive (false);
6050 _control_point_context_menu.popup (event->button.button, event->button.time);
6054 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6056 using namespace Menu_Helpers;
6058 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6063 /* We need to get the selection here and pass it to the operations, since
6064 popping up the menu will cause a region leave event which clears
6065 entered_regionview. */
6067 MidiRegionView& mrv = note->region_view();
6068 const RegionSelection rs = get_regions_from_selection_and_entered ();
6069 const uint32_t sel_size = mrv.selection_size ();
6071 MenuList& items = _note_context_menu.items();
6075 items.push_back(MenuElem(_("Delete"),
6076 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6079 items.push_back(MenuElem(_("Edit..."),
6080 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6081 if (sel_size != 1) {
6082 items.back().set_sensitive (false);
6085 items.push_back(MenuElem(_("Transpose..."),
6086 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6089 items.push_back(MenuElem(_("Legatize"),
6090 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6092 items.back().set_sensitive (false);
6095 items.push_back(MenuElem(_("Quantize..."),
6096 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6098 items.push_back(MenuElem(_("Remove Overlap"),
6099 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6101 items.back().set_sensitive (false);
6104 items.push_back(MenuElem(_("Transform..."),
6105 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6107 _note_context_menu.popup (event->button.button, event->button.time);
6111 Editor::zoom_vertical_modifier_released()
6113 _stepping_axis_view = 0;
6117 Editor::ui_parameter_changed (string parameter)
6119 if (parameter == "icon-set") {
6120 while (!_cursor_stack.empty()) {
6121 _cursor_stack.pop_back();
6123 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6124 _cursor_stack.push_back(_cursors->grabber);
6125 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6126 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6128 } else if (parameter == "draggable-playhead") {
6129 if (_verbose_cursor) {
6130 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6136 Editor::use_own_window (bool and_fill_it)
6138 bool new_window = !own_window();
6140 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6142 if (win && new_window) {
6143 win->set_name ("EditorWindow");
6145 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6147 // win->signal_realize().connect (*this, &Editor::on_realize);
6148 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6149 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6150 win->set_data ("ardour-bindings", bindings);
6155 DisplaySuspender ds;
6156 contents().show_all ();
6158 /* XXX: this is a bit unfortunate; it would probably
6159 be nicer if we could just call show () above rather
6160 than needing the show_all ()
6163 /* re-hide stuff if necessary */
6164 editor_list_button_toggled ();
6165 parameter_changed ("show-summary");
6166 parameter_changed ("show-group-tabs");
6167 parameter_changed ("show-zoom-tools");
6169 /* now reset all audio_time_axis heights, because widgets might need
6175 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6176 tv = (static_cast<TimeAxisView*>(*i));
6177 tv->reset_height ();
6180 if (current_mixer_strip) {
6181 current_mixer_strip->hide_things ();
6182 current_mixer_strip->parameter_changed ("mixer-element-visibility");